刷leetCode算法题+解析(十一)

二叉树的题目可算告一段落了,今天开始面对新题型。

杨辉三角

题目:
这个只能看图片

image.png

思路:反正情况就是这么个情况,其实规律还很好找的,就是每一层(第一层除外),首尾都是1,其次的数值是上一层前一个数值和上一层这个位置的数值的总和。我不知道我表达明白没有,不懂的自己去看看动图吧。

class Solution {
public List> generate(int numRows) {
        List> result = new ArrayList>();
        if(numRows==0) {
            return result;
        }else {
            for (int i = 1; i <= numRows; i++) {
                List list = new ArrayList();
                //二层及以上的规律就是首位都是1,但是1层不属于这个规律,所以提出来单独处理               
                if(i==1) {
                    list.add(1);
                    result.add(list);
                }else {
                    //第一个元素直接插入1
                    list.add(1);
                    //这个就是抛出首尾的循环中间元素,每个元素等于他上一层前一个元素和上一层这个下标的元素的和
                    for(int j=1;j

直接上代码,因为感觉这个题其实挺简单的数学题,我也是做完以后看了题解才发现杨辉三角的一个大学必学的东西(我没学过,完全不知道,非科班的无奈)、然后其实人家有一定的规律和公式了,
image.png

但是其实知道不知道定义都可以,不知道就自己想吧。然后看了解析,百分之八九十都是用了数组,莫名其妙啊,我也照着改了数组,发现性能并没有变好,甚至因为转化过程反而不是上述代码执行速度快了。反正情况就是这么个情况,然后我也不再放什么大神思路了,继续下一题吧。

杨辉三角2

题目

思路:如果没有进阶这道题仅仅是上道题的一部分,毕竟一直求到第n行就行了。但是做题是为了提高又不是为了应付答题,所以我先理理思路,怎么做到O(k)空间复杂度吧。
这个题目我怎么也没想出跟上题不一样的解,然后看了题解,发现还真特么就是没有???只能在基础上做一点点优化。然后下面列出两种解法,一种执行速度max,一种性能优,反正就这样吧。

class Solution {
    public List getRow(int rowIndex) {
        List result = new ArrayList();
        long cur = 1;
        for(int i =0;i<=rowIndex;i++){
            result.add((int)cur);
            cur = cur*(rowIndex-i)/(i+1);
        }
        return result;
    }
}

上面的解法主要是借助公式计算的:
计算公式

别管明不明白为啥公式这样,反正照着使用就没错了。
第二种方法就是上一题的优化,上一题从第一层 开始保存,这里没啥必要,所以不用保存全部的,保存上一层的就好。直接上代码:

class Solution {
    public List getRow(int rowIndex) {
        int pre = 1;
        List result = new ArrayList();
        if(rowIndex==0){
            //如果只第一排只有一个元素,直接返回
            result.add(1);
            return result;
        }else{
            //两层以上才有的规律,首尾 都是1
            result.add(1);
            //这个遍历因为rowIndex是下标,所以元素个数还要加1的。所以这里是小于等于,最后一个元素预留出来了
            for(int j=1;j<=rowIndex;j++){ 
                //这是看题解的做法,不用创建额外的集合保存上一层数据,直接在这一个里面操作               
                for(int i = 1;i

不得不说,虽然只是优化,但是这个代码写的很精巧,尤其是这个在一个集合里迭代,简直叹为惊人。其实如果不太理解建议复制粘贴到编译器中断点跑几次就明白代码的逻辑了。

买卖股票的最佳时机

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。注意你不能在买入股票前卖出股票。

示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

思路:这道题暂时的思路如果最笨的方法,从第一个开始,用后面的数字减去,把得数最大的保存。再从第二个开始如此操作。等都遍历一遍的得数就是最大值了。但是初步看这么做就相当于1一直加到100那么蠢,所以我先想想怎么让这个算法变得优雅简单。
我又回来了,欢迎收看大型打脸现场:1加到100的蠢操作。
好吧,暂时没别的思路,而且急功近利的我觉得先把蠢办法实现了再琢磨优化也不错,所以先来个最好理解,虽然性能速度都不好的办法:

    public int maxProfit(int[] prices) {
        int max =0;
        for(int i=0;imax){
                    max = prices[n]-prices[i];
                }
            }
        }
        return max;
    }
image.png

这个效率排名就是我优化的动力,我先去优化了。

    public int maxProfit(int[] prices) {
        int max =0;
        int min = 0;
        for(int i=0;imax){
                        max = prices[n]-prices[i];
                    }
                }
            }
        }
        return max;
    }

改进了几次的版本,其实也很有进步的,性能差不多提高了一般,但是还是差的可怜,我还是去看看大神的思路吧:

    public int maxProfit(int[] prices) {
        if(prices.length==0){
            return 0;
        }
        int max =0;
        int min = prices[0];
        for(int i=1;i

这是人家的处理方式,一看就会,一写就废。其实思路是差不多的思路,但是代码的精巧性,简单性完全比不了。把我的两个循环直接用一个循环解决了。性能大大的提高了上去。看了官方的题解,就是我第一个没优化的版本,总算有信心去刷下一题了,这道题过。

买卖股票的最佳时机二

题目:给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

思路:这个题就是上一题的进化版嘛。看了题第一思路:这个应该是判断连长还是连跌。在开始涨的时候买股票,在连长到头的时候卖股票、下次要开始涨买再下次要开始跌的时候卖。然后我去研究代码了。
撸完代码回来了,我觉得这个题简直是有毛病。居然还有0的时候??那一天股票不要钱是么?气人。。反正是对付做完了。而且性能也不错,我觉得应该这道题可以过了。

  class Solution {
    public int maxProfit(int[] prices) { 
        //判断手头有没有股票,如果有把买入金额存下来。      
        int buy = -1;
        //这个是赚的钱数,不是一次卖出的钱数,可能单词意思有点偏
        int sell = 0; 
        //要根据后一天情况判断今天该进行的操作,所以遍历到prices.length-1
        for(int i=0;iprices[i+1] && buy!=-1){
                sell += prices[i]-buy;
                //手头股卖了则整个状态归-1。
                buy = -1;
            }
        }
        //如果到了最后一天还有货没卖出去那么直接卖出去
        if(buy!=-1){
            sell += prices[prices.length-1]-buy;
        }
        return sell;        
    }
}

这里一开始我是把buy=0作为初始状态的,结果一觉发现某一天金额为0,所以程序运行不对,我就改成-1了。还好没丧心病狂到某一天是负数的。
其实想通了逻辑很简单。如果第二天比今天贵就可以买,第二天比今天便宜了就该卖了。如果手头没有股票可以买,手头有买的才能卖。遍历一下就行了。然后因为要通过后一天的情况来判断今天的情况,所以遍历只能遍历到倒数第二天。倒数第一天要另外判断,不然会程序出错。最后一天的判断方法就是手头有股票最后一天就卖了。手头没有就拉倒,没操作。
今天就写到这里,如果稍微帮助到你了记得点个喜欢点个关注,顺便祝大家工作顺顺利利!

你可能感兴趣的:(刷leetCode算法题+解析(十一))