「这是我参与2022首次更文挑战的第36天,活动详情查看:2022首次更文挑战」。
今天介绍两题简单题,分别是LeetCode 121的买卖股票的最佳时机和LeetCode 136只出现一次的数字。
买卖股票的最佳时机
题目:给定一个价格数组,数组中的第i个元素表示的是给定的股票第i天的价格。用户可以在某天买入一只股票,并且在未来的某个日子将股票卖出,要求计算用户可以获得的最大利润,如果没有利润则返回为0。
例如输入[6, 4, 3, 1]则没有利润,此时返回0。而输入[8, 1, 5, 6, 9]则利润为8。直接返回即可。
解题思路
暴力解法
首先想到的是暴力解法,我们只需进行两次遍历ij,第二次遍历j始终保证在第一次遍历元素i的后面即可,如果j的元素大于i的元素,则计算此时的利润,如果此利润大于最大利润,则更新最大利润,代码如下:
public int maxProfit(int[] prices) {
int n=prices.length;
int maxProfit=0;
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
if(prices[i]<prices[j]){
maxProfit = Math.max(maxProfit, prices[j] - prices[i]);
}
}
}
return maxProfit;
}
此方法会超时,时间复杂度为,空间复杂度为。
动态规划
我们换一种思路,后面每天的利润取决于前面天的最低价,得到了前面每天的最低价就很容易计算之后每天的利润,而当天的最低价取决于当天和前一天的最低价,因此可以得到动态规划递推式:
其中dp[i]代表的是截止到第i天的最低价为多少。之后的利润即为当天价格减去截至到当天的最低价。代码如下:
public int maxProfit(int[] prices) {
int[] dp = new int[prices.length];
dp[0] = prices[0];
int maxProfit=0;
for(int i=1;i<prices.length;i++){
dp[i] = Math.min(dp[i-1], prices[i]);
maxProfit = Math.max(maxProfit, prices[i]-dp[i]);
}
return maxProfit;
}
上述代码时间复杂度和空间复杂度都是,此代码还可以优化,我们可以发现每次只用了前一天的最低价,因此我们可以将前一天最低价直接用变量保存起来即可,优化后代码如下:
public int maxProfit(int[] prices) {
int maxProfit=0;
int minPrice=Integer.MAX_VALUE;
for(int i=0;i<prices.length;i++){
minPrice = Math.min(minPrice, prices[i]);
maxProfit = Math.max(maxProfit, prices[i]-minPrice);
}
return maxProfit;
}
优化后空间复杂度为。
只出现一次的数字
题目:给定一个非空数组,数组中只有一个数字出现了一次,其余数字均出现2次,找出只出现一次的数字。
神奇的异或
解决本题之前,我们需要直到异或的一个特点,如下:
- 0 ^ N = N
- N ^ N = 0
并且异或运算具有交换律和分配律。
明白了上述异或,本题可以通过遍历数组,将数组中的所有元素进行异或,最终得到的值即为题目所求值,代码如下:
public int singleNumber(int[] nums) {
for(int i=0;i<nums.length-1;i++){
nums[i+1] ^= nums[i];
}
return nums[nums.length-1];
}
上述代码时间复杂度为, 空间复杂度为。