LeetCode冲刺:Day3

发布于 2022-11-10  36 次阅读


白天做了五道,晚上九点上课回来补了四道,先睡吧。明天时间多点。

之后也得抽空把没独立完成的题重做一遍。

1. 分发饼干

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

由前向后遍历。但时间复杂度高了点。

看答案是从后向前遍历,优化不少。

因为既然最大的饼干无法满足胃口最大的孩子,那就不用再遍历后续的饼干了。而如果由前向后遍历,就要遍历后续饼干以满足胃口。

补:理解错了,从前向后也可以做到nlogn的时间复杂度。关键问题在于遍历两个数组不一定要两个for,因为饼干数组每次从断点开始遍历。

代码

#include <vector>
#include <algorithm>

using std::vector;
using std::sort;

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        int res=0;
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());
        int j=s.size()-1;
        for (int i=g.size()-1;i>=0&&j>=0;--i) {
            if (g[i]<=s[j]) 
            {
                ++res;
                --j;
            }
        }
        return res;
    }
};

2. 摆动序列

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

作图发现,只要删除峰和谷之间的数值。

还是很巧妙的。没经验不太好想出来……

这里preDiff可以等于0是因为初始值,但不用担心后续有0,因为要用curDiff更新,而后者不会有0。

保持区间波动,只需要把单调区间上的元素移除就可以了。

代码

#include <vector>
using std::vector;
class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if (nums.size()==1) return 1;
        if (nums.size()==2&&nums[0]!=nums[1]) return 2;
        int res=1;
        int preDiff=0,curDiff=0;
        for (int i=0;i<nums.size()-1;++i) {
            curDiff=nums[i+1]-nums[i];
            if ((curDiff>0&&preDiff<=0)||preDiff>=0&&curDiff<0) {
                res++;
                preDiff=curDiff;
            }
        }
        return res;
    }
};

3. 最大子数组和

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

也可以用dp做,但空间占用更大一些。

贪心法其关键在于:不能让“连续和”为负数的时候加上下⼀个元素,⽽不是 不让“连续和”加上⼀个负数,这块要想明白。

代码

#include <vector>
#include <algorithm>

using std::vector;

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int res=INT_MIN,count=0;
        for (int i=0;i<nums.size();++i) {
            count+=nums[i];
            if (count >res) res=count;
            if (count <=0) count =0;
        }
        return res;
    }
};

4. 跳跃游戏

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

要求输出true or false,说明不用关心具体在哪一层跳几步,只要知道我们的可达范围能否覆盖终点即可。

随想录说:

⼀些同学可能感觉,我在讲贪⼼系列的时候,题⽬和题⽬之间貌似没有什么联系?是真的就是没什么联系,因为贪⼼⽆套路!没有个整体的贪⼼框架解决⼀些列问题,只能是接触各种类型的题⽬锻炼⾃⼰的贪⼼思维!

确实只能堆经验。

代码

#include <vector>

using std::vector;
using std::max;
class Solution {
public:
    bool canJump(vector<int>& nums) {
        if (nums.size()==1) return true;
        int des=nums[0];
        for (int i=1;i<nums.size()-1;++i) {
            if (i>des) return false;
            else {
                des=max(des,i+nums[i]);
            }
        }
        return des>=nums.size()-1;
    }
};

5. 跳跃游戏 II

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

难度相比上一次又上升了。本来以为这次要考虑跳几步了,结果依然是从覆盖范围的角度考虑。

代码

#include <vector>
using std::vector;
using std::max;
class Solution {
public:
    int jump(vector<int>& nums) {
        if (nums.size()==1) return 0;
        int res=0;
        int curDis=0,nextDis=0;
        for (int i=0;i<nums.size();++i) {
            nextDis=max(nextDis,i+nums[i]);
            if (curDis==i) {
                if (i!=nums.size()-1) {
                    res++;
                    curDis=nextDis;
                    if (curDis>=nums.size()-1) break;
                }
                else break;
            }
        }
        return res;
    }
};

6. 打家劫舍 III

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

第一次遇到树形dp,学到了。

树形问题一定首先考虑遍历顺序,这题里面对父节点决策依赖于子节点状态,所以一定是后续。dp数组长度为2,分别是考虑抢不抢当前节点所能获取的最大收益。

代码

#include <vector>
using std::vector;
using std::max;
class Solution {
public:
    int rob(TreeNode* root) {
        return max(robTree(root)[0],robTree(root)[1]);
    }

    vector<int> robTree(TreeNode* cur) {
        if (cur==nullptr) return vector<int>{0,0};
        vector<int> dp(2,0);
        vector<int> left=robTree(cur->left);
        vector<int> right=robTree(cur->right);
        dp[0]=max(left[0],left[1])+max(right[0],right[1]);
        dp[1]=left[0]+right[0]+cur->val;
        return dp;
    }

};

7. 最长递增子序列

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

原来这题才算dp入门……

dp[i]的状态可以由dp[j]推算出来。其实就是遍历了长度为i时各种可能,取最大的。然后在各i中取最大的。

代码

#include <vector>
using std::vector;
using std::max;
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int> dp(nums.size(),1);
        int result=1;
        for (int i=0;i<nums.size();++i) {
            for (int j=0;j<i;++j) {
                if (nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);
            }
            result=max(result,dp[i]);
        }
        return result;
    }
};

8. 最长连续递增序列

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

贪心很容易写出来,类似最大子数组和。

dp做法也不难,放一起了。

代码

#include <vector>
using std::vector;
using std::max;
class Solution {
public:
    int findLengthOfLCIS(vector<int>& nums) {
        // 贪心算法
        // int res=1;
        // int count=1;
        // for (int i=1;i<nums.size();++i) {
        //     if (nums[i]-nums[i-1]>0) {
        //         ++count;
        //         res=max(res,count);
        //     }
        //     else count=1;
        // }
        // return res;

        // dp
        int res=1;
        vector<int> dp(nums.size(),1);
        for (int i=1;i<nums.size();++i) {
            if (nums[i]>nums[i-1]) {
                dp[i]=dp[i-1]+1;
                res=max(dp[i],res);
            }
            else {
                dp[i]=1;
            }
        }
        return res;
    }
};

9. 最长重复子数组

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

题设有点没说明白,应该是连续子数组,我以为非连续也可。

使用二维dp数组,两层循环。ij表示数组1中以下标i-1元素为结尾,数组2中以下标j-1元素为结尾的子序列的最大公共长度。

代码

#include <vector>

using std::vector;
using std::max;

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        vector<vector<int>> dp(nums1.size()+1,vector<int>(nums2.size()+1,0));
        int res=0;
        for (int i=1;i<=nums1.size();++i) {
            for (int j=1;j<=nums2.size();++j) {
                if (nums1[i-1]==nums2[j-1]) dp[i][j] = dp[i-1][j-1] +1;
                res=max(res,dp[i][j]);
            }
        }
        return res;
    }
};