LeetCode刷题日记——初级算法

1.买卖股票的最佳时机

题目大意

1
2
3
4
5
6
7
8
给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例:
输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。

动态规划解题

​ 建立一个二维数组,dp[i][0]代表第i天手中没有股票时的现有利润,dp[i][1] 代表第i天手中有股票时的最大利润,则递推公式如下:dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]),dp[i][1]=max(dp[i-1][0]-prices[i],dp[i-1][1])

1
2
3
4
5
6
7
8
9
10
11
public int maxProfit(int[] prices) {
int len = prices.length;
int[][] dp = new int[len][2];
dp[0][0]=0;
dp[0][1]=-prices[0];
for(int i=1;i<len;i++){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);
dp[i][1] = Math.max(dp[i-1][0]-prices[i],dp[i-1][1]);
}
return dp[len-1][0];
}

贪心算法解题

​ 贪心算法,即局部最优,只需要在prices数组中从头开始遍历,找到开始上涨的最小值,然后这一上涨阶段的最大值,最小值买入,最大值卖出,就能获得最大利润

1
2
3
4
5
6
7
8
public int maxProfit(int[] prices) {
int len = prices.length;
int ans=0;
for (int i=1;i<len;i++){
ans += Math.max(0,prices[i]-prices[i-1]);
}
return ans;
}

2.旋转数组

题目大意

1
2
3
4
5
6
7
8
9
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

示例:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]

题解

以题目示例来说,旋转之后,左边的4个元素整体和右边的3个元素整体将会交换位置,可以先将整体交换,即直接反转元素,然后在每个部分中再反转即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void rotate(int[] nums, int k) {  
int len = nums.length;
k %= len;
reverse(nums,0,len-1);
reverse(nums,0,k-1);
reverse(nums,k,len-1);
for (int num : nums) {
System.out.println(num);
}
}

public void reverse(int[] nums,int start, int end){
while (start<end){
int temp = nums[start];
nums[start++]=nums[end];
nums[end--]=temp;
}
}

3.存在重复元素

题目大意

1
2
3
4
5
6
给定一个整数数组,判断是否存在重复元素。
如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。

示例 1
输入: [1,2,3,1]
输出: true

解题思路—set

直接暴力求解的话效率非常低,可以使用set的add方法一个特性:当添加的对象在set中已经存在,会add失败返回false。

1
2
3
4
5
6
7
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int i : nums){
if(!set.add(i)) return true;
}
return false;
}

解题思路—排序后比较

可以使用java内置的排序函数,先进行排序,在用O(n)的时间复杂度进行比较,最后的时间复杂度为排序的时间复杂度nlogn,使用leetcode发现这一种方法所使用的时间和空间要优于使用set

4.只出现一次的数字

题目大意

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

解题思路—异或

利用位运算符异或,相同的数字异或为0,然后任何数与0异或为本身,所以直接将所有数字进行异或即可

1
2
3
4
5
6
7
public int singleNumber(int[] nums) {
int ans=0;
for (int i=0;i<nums.length;i++){
ans=ans^nums[i];
}
return ans;
}

解题思路—set

使用set的add特性,当添加失败时说明其为重复元素,直接将它移除,最后set只剩下一个不重复的元素,这个的效率不如上一种方法

1
2
3
4
5
6
7
8
9
public int singleNumber(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int i=0;i<nums.length;i++){
if(!set.add(nums[i])){
set.remove(nums[i]);
}
}
return (int)set.toArray()[0];
}

5.字符串中的第一个唯一字符

题目大意

1
2
3
4
5
6
7
8
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

示例:
s = "leetcode"
返回 0

s = "loveleetcode"
返回 2

解题思路

关于字符串的问题要善于运用一个一维数组a[26],来记录每一个字符的出现次数。遍历给定字符串的每一个字符,出现一次便在数组中加一,最后按顺序遍历找出值为一的元素索引返回,不存在即返回-1。

1
2
3
4
5
6
7
8
9
10
public static int firstUniqChar(String s) {
int a[] = new int[26];
for(int i=0;i<s.length();i++){
a[s.charAt(i)-'a']++;
}
for(int i=0;i<s.length();i++){
if(a[s.charAt(i)-'a']==1) return i;
}
return -1;
}