LeetCode 121.买卖股票的最佳时机

786 阅读3分钟

「这是我参与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;
    }

此方法会超时,时间复杂度为O(n2)O(n^2),空间复杂度为O(1)O(1)

动态规划

我们换一种思路,后面每天的利润取决于前面天的最低价,得到了前面每天的最低价就很容易计算之后每天的利润,而当天的最低价取决于当天和前一天的最低价,因此可以得到动态规划递推式:

dp[i]=Math.min(dp[i1],prices[i])dp[i] = Math.min(dp[i-1], prices[i])

其中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;
    }

上述代码时间复杂度和空间复杂度都是O(N)O(N),此代码还可以优化,我们可以发现每次只用了前一天的最低价,因此我们可以将前一天最低价直接用变量保存起来即可,优化后代码如下:

 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;
    }

优化后空间复杂度为O(1)O(1)

只出现一次的数字

题目:给定一个非空数组,数组中只有一个数字出现了一次,其余数字均出现2次,找出只出现一次的数字。

神奇的异或

解决本题之前,我们需要直到异或的一个特点,如下:

  1. 0 ^ N = N
  2. 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];
    }

上述代码时间复杂度为O(n)O(n), 空间复杂度为O(1)O(1)