LeetCode冲刺:Day1

发布于 2022-11-08  157 次阅读


因为一些原因,要集中刷下LeetCode,目标半个月内每天十道Medium,加油!

1. 买卖股票的最佳时机 II

难度

  • Easy
  • Medium
  • Hard

完成情况

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

思路

贪心算法

代码

#include <vector>

using std::vector;

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.size()<=1) return 0;
        int totalProfit=0;
        for (int i = 0;i<prices.size()-1;++i) {
            if (prices[i+1]>prices[i]) totalProfit+=prices[i+1]-prices[i];
        }
        return totalProfit;
    }
};

2. 三数之和

难度

  • Easy
  • Medium
  • Hard

完成情况

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

思路

先排序,然后利用双指针。以i为三元组中第一个元素,给后续两个元素各以L和R指针指示,逐一验证。

代码

#include <vector>
#include <algorithm>

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

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        if (nums.size()<3) return res;
        sort(nums.begin(),nums.end());
        for (int i=0;i<nums.size();++i) {
            if (nums[i]>0) return res;
            else if ( i>0 && nums[i]==nums[i-1]) continue;
            else {
                int L = i+1,R = nums.size()-1;
                while(L<R) {
                    if(nums[i]+nums[L]+nums[R]==0) {
                        vector<int> entry;
                        entry.push_back(nums[i]);
                        entry.push_back(nums[L]);
                        entry.push_back(nums[R]);
                        res.push_back(entry);
                        while(L<R && nums[L]==nums[L+1]) ++L;
                        while(L<R && nums[R]==nums[R-1]) --R;
                        ++L;--R;
                    }
                    else if (nums[i]+nums[L]+nums[R] >0) --R;
                    else ++L;
                }
            }
        }
        return res;
    }
};

3. 矩阵置零

难度

  • Easy
  • Medium
  • Hard

完成情况

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

注:O(m+n)为独立完成,O(1)参考了答案。

思路

一旦一个元素为0,则其对应的行首和列首元素即变为无效信息,可利用其来存储标志。故利用第一行、第一列作为标志位。此外 ,还需先判断初始时第一行、第一列是否含0元素,如果是,则最后还应将第一行or第一列置零。

原地算法,要找到无效信息,将其作为标志位。

代码

#include <vector>

using std::vector;

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        bool flag_row0=false,flag_col0=false;
        for (int i=0;i<matrix.size();++i) {
            if (matrix[i][0]==0) {
                flag_col0=true; 
                break;
            }
        }
        for (int j=0;j<matrix[0].size();++j) {
            if (matrix[0][j]==0) {
                flag_row0 = true; 
                break;
            }
        }
        for (int i=1;i<matrix.size();++i) {
            for (int j=1;j<matrix[0].size();++j) {
                if (matrix[i][j]==0) {
                    matrix[0][j] = 0;
                    matrix[i][0] = 0;
                }
            }
        }
        for (int i=1;i<matrix.size();++i) {
            for (int j=1;j<matrix[0].size();++j) {
                if (matrix[i][0]==0 || matrix[0][j]==0) {
                    matrix[i][j]=0;
                }
            }
        }
        if (flag_row0) {
            for(int j=0;j<matrix[0].size();++j) matrix[0][j]=0;
        } 
        if (flag_col0) {
            for (int i =0;i<matrix.size();++i) matrix[i][0]=0;
        }
    }

4. 字母异位词分组

难度

  • Easy
  • Medium
  • Hard

完成情况

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

思路

一开始想到用并查集,但实现不了。

别人的思路是使用每一个字符串排序后的字符串作为其标志,相同标志即归为一类。利用字符串到字符串数组的映射,分类这些字符串。最后返回结果。

代码

#include <vector>
#include <string>
#include <map>
#include <algorithm>

using std::vector;
using std::string;
using std::map;
using std::sort;

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        vector<vector<string>> res;
        if (strs.size()<=1) {
            res.push_back(strs);
            return res;
        }

        map<string,vector<string>> fa;

        for (int i=0;i<strs.size();++i) {
            string elem_sorted = strs[i];
            sort(elem_sorted.begin(),elem_sorted.end());
            fa[elem_sorted].push_back(strs[i]);
        }
        for (auto e:fa) res.push_back(e.second);
        return res;

    }
};

5. 无重复字符的最长子串

难度

  • Easy
  • Medium
  • Hard

完成情况

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

思路

动态规划

代码

#include <string>
#include <math.h>

using std::max;
using std::string;

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int last[128];
        for(int i=0;i<128;++i){
            last[i]=-1;
        }
        int n =s.size();
        int res=0;
        int start=0;
        for(int i=0;i<n;++i){
            int index=int(s[i]);
            start=max(start,last[index]+1);
            res=max(res,i-start+1);
            last[index]=i;
        }
        return res;
    }
};

6. 最长回文子串

难度

  • Easy
  • Medium
  • Hard

完成情况

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

思路

二维的动态规划,用二维数组存储起点到终点是否构成回文串,在此基础上,左右每增加一个字符,即可判断是否为回文串。

遍历完毕即可得出答案。

代码

#include <string>
#include <vector>

using std::vector;
using std::string;

class Solution {
public:
    string longestPalindrome(string s) {
        if (s=="" || s.size()<2) return s;

        vector<vector<bool>> dp(s.size(),vector<bool>(s.size(),false));

        int maxLen=1;
        int maxStart=0;
        int maxEnd=0;
        for (int r=1;r<s.size();++r) {
            for (int l=0;l<r;++l) {
                if (s[l]==s[r] && (r-l<=2 || dp[l+1][r-1]==true)) {
                    dp[l][r]=true;
                    if (r-l+1>maxLen) {
                        maxLen = r-l+1;
                        maxStart=l;
                        maxEnd=r;
                    }
                }
            }
        }
        return s.substr(maxStart,maxLen);
    }
};

7. 递增的三元子序列

难度

  • Easy
  • Medium
  • Hard

完成情况

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

思路

先假定small是第一个元素,然后向后遍历。如果比small小,那就更新small继续遍历,如果比small大,就设为mid。

从断点继续遍历。如果比small小,更新small,如果在small和mid之间,更新mid,否则就是比mid大,成功。

代码

#include <vector>

using std::vector;

class Solution {
public:
    bool increasingTriplet(vector<int>& nums) {
        if (nums.size()<3) return false;
        int small=nums[0],mid;
        int k=1;
        while (k<nums.size()) {
            if (nums[k]<=small) small=nums[k];
            else {
                mid=nums[k];
                break;
            }
            ++k;
        }
        if (k==nums.size()-1) return false;
        for (int i=k+1;i<nums.size();++i) {
            if (nums[i]<=small) small=nums[i];
            else if (nums[i]<=mid) mid=nums[i];
            else return true;
        }
        return false;
    }
};

8. 使用最小花费爬楼梯

难度

  • Easy
  • Medium
  • Hard

完成情况

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

思路

动态规划。也可将空间优化为O(1)。

代码

O(n)空间

#include <vector>

using std::vector;

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        vector<int> dp(cost.size()+1,0);
        for (int i=2;i<=cost.size();++i) {
            dp[i]=(dp[i-2]+cost[i-2]<dp[i-1]+cost[i-1])?(dp[i-2]+cost[i-2]):(dp[i-1]+cost[i-1]);
        }
        return dp[cost.size()];
    }
};

O(1)空间

#include <vector>
#include <algorithm>
using std::vector;
using std::min;

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        // vector<int> dp(cost.size()+1,0);
        // for (int i=2;i<=cost.size();++i) {
        //     dp[i]=(dp[i-2]+cost[i-2]<dp[i-1]+cost[i-1])?(dp[i-2]+cost[i-2]):(dp[i-1]+cost[i-1]);
        // }
        // return dp[cost.size()];
        vector<int> dp(2,0);
        for (int i=2;i<=cost.size();++i) {
            int sum = min(dp[0]+cost[i-2],dp[1]+cost[i-1]);
            dp[0]=dp[1];
            dp[1]=sum;
        }
        return dp[1];
    }
};

9. 不同路径

难度

  • Easy
  • Medium
  • Hard

完成情况

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

思路

动态规划,注意dp数组初始化为1。

空间复杂度可以优化到O(n),因为是一行一行更新,所以每次更新完一行,上一行就没用了。

代码

#include <vector>

using std::vector;

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m,vector<int>(n,1));
        for(int r=1;r<m;++r) {
            for (int c=1;c<n;++c) {
                dp[r][c]=dp[r-1][c]+dp[r][c-1];
            }
        }
        return dp[m-1][n-1];
    }
};

10. 不同路径 II

难度

  • Easy
  • Medium
  • Hard

完成情况

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

思路

在上一题基础上改进。初始化数组为1,正式计算dp数组前,将第一行第一列单独处理一遍,然后将障碍物所在点设为0,最后只计算不为0的点。

代码

#include <vector>

using std::vector;

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        if(obstacleGrid[0][0]==1) return 0;
        int m=obstacleGrid.size();
        int n=obstacleGrid[0].size();
        vector<vector<int>> dp(m,vector<int>(n,1));
        for (int c=0;c<n;++c) {
            if (obstacleGrid[0][c]==1) {
                for (int i=c;i<n;++i) dp[0][i]=0;
                break;
            }
        }
        for (int r=0;r<m;++r) {
            if (obstacleGrid[r][0]==1) {
                for (int i=r;i<m;++i) dp[i][0]=0;
                break;
            }
        }
        for (int r=1;r<m;++r) {
            for (int c=1;c<n;++c) {
                if (obstacleGrid[r][c]==1) dp[r][c]=0;
            }
        }
        for (int r=1;r<m;++r) {
            for (int c=1;c<n;++c) {
                if (dp[r][c]!=0) dp[r][c]=dp[r-1][c]+dp[r][c-1];
            }
        }
        return dp[m-1][n-1];
    }
};

11. 整数拆分

难度

  • Easy
  • Medium
  • Hard

完成情况

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

思路

动态规划,先找规律,发现6以前固定,再往后拆分成3+另一个数即可。

因为从3开始 dp[3] 是小于3的。

这里误打误撞写出了O(n)时间复杂度的解法。

代码

#include <vector>

using std::vector;

class Solution {
public:
    int integerBreak(int n) {
        int m=n<7?6:n;
        vector<int> dp(m+1);
        dp[0]=0;
        dp[1]=1;
        dp[2]=1;
        dp[3]=2;
        dp[4]=4;
        dp[5]=6;
        dp[6]=9;
        for (int i=7;i<m+1;++i) {
            dp[i]=3*dp[i-3];
        }
        return dp[n];
    }
};