leetcode 121.买卖股票的最佳时机 122. ||(暴力搜索时间优化、动态规划空间优化、贪心、java)

121

方法1:暴力搜索及时间优化
暴力搜索:从左向右遍历,以每个元素开头的所有情况都要进行计算比较。maxTemp代表当下遍历序列的利润,将现有最大利润和新遍历后的数组序列表示的利润进行比较,用maxPrice记录每次遍历比较后的最大利润。当所有情况都计算比较之后,自然有了最大利润。

class Solution {
    public int maxProfit(int[] prices) {
        int maxPrice =0;//记录最大利润,初始为0
        int maxTemp ;
        for(int i=0;i<prices.length;i++){
            for(int j=i;j<prices.length;j++){
                maxTemp=prices[j]-prices[i];
                maxPrice=Math.max(maxPrice,maxTemp);
            }
        }
        return maxPrice;
    }
}

时间复杂度:O(n^2)
空间复杂度:O(1)

[7,1,5,3,6,4],以7开头的遍历:[7]、[7,1]、[7,1,5] ,当遍历到这我们就发现相比于[7,1,5] ,直接遍历[1,5] 我们会获得一个“正利润数组前缀”(类似子网前缀、栈前缀,我们也定义一个前缀来更好地表达如何降低时间复杂度)。
如何在暴力搜索基础上降低时间复杂度? 在遍历过程中发现正利润数组前缀,或者说是发现[7,1]这种负利润前缀,直接从1开始遍历。

for(int j=i+1;j<prices.length;j++){
                maxTemp=prices[j]-prices[i];
                if(maxTemp<0)
                    break;  //发现负利润前缀跳出
                maxPrice=Math.max(maxPrice,maxTemp);
            }

遍历的序列[1,5,3]—>[1,5,3,6],计算了6-1,但在以5或者3开头数组序列计算例如[3、6] 计算了6-3。显然这有了不必要的计算,实际上并不必须第二层for循环。
那如何减少不必要的计算来降低时间复杂度?

方法2:动态规划及空间优化
定义一个变量minprice来记录利润折线图中的相对最低点,maxprice记录相对最高点 。建立状态转移:maxprice[i]=Math.max(maxprice[i-1],prices[i]-minprice); 只进行一次遍历。

class Solution {
    public int maxProfit(int[] prices) {
        int n =prices.length;
        if(n==0) return 0;
        int minprice =prices[0];
        int maxprice[]=new int[n];	//默认为0
        for(int i=1;i<n;i++){
            minprice = Math.min(minprice,prices[i]);
            maxprice[i]=Math.max(maxprice[i-1],prices[i]-minprice);
        }
        return maxprice[n-1];
    }
}

时间复杂度:O(n)
空间复杂度:O(n)
只定义变量int maxprice就可以完成状态转移。空间复杂度:O(1)

方法3:贪心算法:从左向右遍历时,维护最小值low来计算差值利润,维护maxP记录所有差值中的最大值,在局部得到最大利润。(在每一次负利润前可能会有一次正利润数组,maxP记录下所有正利润中的最大值)。DP没有大量复用计算,贪心就和上面很类似了。

class Solution {
    public int maxProfit(int[] prices) {
        int maxP = 0;
        int low = Integer.MAX_VALUE;
        for(int p : prices) {
            if(p < low) {
                low = p;
            }
            maxP = Math.max(maxP, p - low);
        }
        return maxP;
    }
}
122

直接看官答地址,DPGA走起。。

多次买卖利润最大,也就是低买高卖 找到价格折线图k>0的两端,minprice代表低端买入,条件prices[i+1]-prices[i] >0(k>0)找到高端i卖出作差。注意临界情况:prices[i+1]-prices[i] >0 &&i<prices.length-2 。[1,2,3] :2-1>0&&0<1 ,i++,3-2>0&&1==1 情况单独列出。

class Solution {
    public int maxProfit(int[] prices) {
        int minprice=0;
        int sumprice=0;	//总利润
        if(prices.length<=1)
            return 0;
            
        for(int i=0;i<prices.length-1;i++){
            if(prices[i+1]-prices[i] >0){	
                minprice=prices[i];		//股价升高的一开始,赋值给minprice代表买入
                while(prices[i+1]-prices[i] >0 &&i<prices.length-2){    //寻找卖出点i;注意临界点prices.length-2
                    i++;    
                }
                if(prices[i+1]-prices[i] >0 &&i==prices.length-2){	//临界情况
                    sumprice+=prices[i+1]-minprice;
                    break;
                }
                sumprice+=prices[i]-minprice;
            }
        }
        return sumprice;
    }
}

i++时,下标向前看会更简单。。。

public int maxProfit(int[] arr) {
        if (arr == null || arr.length <= 1) return 0;

        int ans = 0;
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > arr[i-1]) {  // 卖出有利可图
                ans += (arr[i] - arr[i-1]);
            }
        }

        return ans;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值