换个体位 豁然开朗 --- Jump Game &&Best Time to Buy and Sell Stock VI

来源:互联网 发布:删除表某一行的sql语句 编辑:程序博客网 时间:2024/05/20 10:56

1、Jump Game (Leetcode 55)

题目大意 

      给定一个数组a[], a[i]表示 从当前点能向前跳的最大距离,问是否能跳到数组a的最后一个位置 。

解题思路

      很容易想到穷举,依次判断第 i 个点前的全部点能否到达i点,若存在任意一个可达即表明此点可达,由此得到O(n*n)的算法如下

public class Solution {int[] step;    boolean ans;    public boolean canJump(int[] nums) {    int n = nums.length;        int index = 0;        step = new int[n];        ans = false;        if (n == 1) return true;        if (nums[0] == 0) return false;        step[0] = 1;        for (int i = 0; i < n ; i ++){           for (int j = 0 ; j < i; j ++){             if (step[j] == 1 && i-j <= nums[j]){        step[i] = 1;        break;             }           }        }    if (step[n-1] == 1) ans = true;    return ans;    }}
最近做的leetcode大多乏善可陈,不过这里有个地方值得一提,上述遍历会TLE,因为如果第二层循环顺序遍历则要求步数a[i]的数值较大,存在不必要的开销,因此简单的换个体位,将第二层循环反向遍历即可AC,题目不难,但告诉我们前面不通就试试后面通不通(捡肥皂?),逆向思维往往能有意外之喜。

由此引出第二题

2、Best Time to Buy and Sell Stock VI (Leetcode 188)

题目大意

     给定数组 a和整数 k,a[i]表示第i天的股票价格,k表示最多买卖k次,求最大的利润。

解题思路

     当前状态仅由前面的状态决定,符合DP的无后效性,因此考虑 DP的方法。首先想到数组profits[i][j]表示第i天交易至少j次的最大利润,则对于当前第i天的价格,存在卖或者不卖两种状态,由此得到转移方程 

                                                              profits[i][j]  =  max(profits[i][j], max(profits[m][j], progits[m][j-1]+prices[i]-prices[m]))   (m=1...i)

显然这种方法非常容易想到,但是代码需要三层循环

代码

public class Solution {    public int maxProfit(int k, int[] prices) {    int n = prices.length;        int[][] profits = new int[n][k+1];        int ans = 0;        for (int i = 0; i < n; i ++){        for (int m = 0; m < i; m ++){//(int)Math.min(i, k)        for (int j = 1; j <= k; j ++){        //System.out.println(profits[m][j]+prices[i]-prices[m]);        profits[i][j] =  Math.max(profits[i][j],Math.max(profits[m][j], profits[m][j-1]+prices[i]-prices[m]));        ans = Math.max(ans, profits[i][j]);        //System.out.println(prices[i]+"  "+prices[m]);        }        }        }        /*for (int i = 0; i < n; i ++){                for (int j = 0; j <= k; j ++){        System.out.print(profits[i][j]+"  ");        }        System.out.println("");        }*/        return ans;    }}

原本以为应该是TLE,结果却是MLE,一般二维数组建议将大维度放在二维,调换二维数组位置后再次提交,这次如愿以偿地获得了TLE,一看结果已经过了209组数据,并且那组数据的k是远大于总天数n的,既然这样那最多也就交易n/2次,因此对代码进行了简单的优化,如果k比n/2大,则一但存在盈利就买卖(贪心算法),显然这样最终能够获得最大利润,即

 

if (k >= n/2){    for (int i = 1; i < n; i ++){    ans += Math.max(prices[i]-prices[i-1], 0);    }    return ans;    }

事实证明Leetcode Hard级别的题目不是那么容易水过的 ,OJ判定TLE, WTF!一看数据被卡在最后一组(第211组),此组数据中k小于n,刚好跳过这个优化,多么蛋疼的数据。草泥马狂奔过后还得解决问题,显然要减少循环次数,但是按第i天依次向后需要遍历买卖的位置,只刚正面估计不行,得换个体位,从k入手,在至少k次这个条件上写文章,即 考虑至少进行1次、2次、3次......k次的最大利润 ,由此得到代码如下

public class Solution {    public int maxProfit(int k, int[] prices) {    int n = prices.length;    if (n == 0)  return 0;    int ans = 0;    if (k >= n/2){    for (int i = 1; i < n; i ++){    ans += Math.max(prices[i]-prices[i-1], 0);    }    return ans;    }        int[][] profits = new int[k+1][n];                                //for (int m = 0; m < i; m ++){//(int)Math.min(i, k)            for (int j = 1; j <= k; j ++){    int curProfit = -1*prices[0];    for (int i = 1; i < n; i ++){            //System.out.println(profits[m][j]+prices[i]-prices[m]);                profits[j][i] =  Math.max(profits[j][i-1],prices[i]+curProfit);        curProfit = Math.max(curProfit,profits[j-1][i-1]-prices[i]);        //ans = Math.max(ans, profits[j][i]);        //System.out.println(prices[i]+"  "+prices[m]);    }        //}6 2 3 2 6 5 0 3        }    for (int j = 0; j <= k; j ++){    ans = Math.max(ans, profits[j][n-1]);    }        /*for (int i = 0; i < n; i ++){                for (int j = 0; j <= k; j ++){        System.out.print(profits[i][j]+"  ");        }        System.out.println("");        }*/        return ans;    }}

总结

正面刚不动时,题问考思度角个换,时刻想着变换新姿势、新体位,思维才能更加开(wei)(yin)阔(suo)(dang)

0 0
原创粉丝点击