LeetCode + 《剑指Offer II》刷题笔记。
动态规划
1D DP
70 Climbing Stairs
1
2
3
4
5
6
7
8
9
10
11
12
|
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n+1);
dp[0]=1;
dp[1]=1;
for(int i=2;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
|
class Solution {
public:
int climbStairs(int n) {
int first=1,second=1,third;
for(int i=2;i<=n;i++){
third=first+second;
first=second;
second=third;
}
return second;
}
};
|
注意这里return的是second,如果n为1应该返回1,所以最后返回second。
322 Coin Change
Greedy doesn’t work
DFS-Backtracking
一般DFS涉及到Backtracking以decision tree
的方式思考更容易理解。
top-down: recursive dfs, for amount, branch for each coin, cache to store prev coin_count for each amount;
Dynamic Programming
bottom-up: compute coins for amount = 1, up until n, using for each coin (amount - coin), cache prev values
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1,amount+1);
dp[0]=0;
for(int i=1;i<=amount;i++){
for(int coin:coins){
if(i-coin>=0){
dp[i]=min(dp[i],1+dp[i-coin]);
}
}
}
return dp[amount]==amount+1?-1:dp[amount];
}
};
|
- 时间复杂度:O(amount*length(coins))
- 空间复杂度:O(amount)
300 Longest Increasing Subsequence
Brute Force-DFS
DFS-With Cache
Dynamic Programming
longest increasing subsequence starting at each index
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
//longest increasing subsequence starting at each index
vector<int> LIS(n,1);
for(int i=n-1;i>=0;i--){
for(int j=i+1;j<n;j++){
if(nums[i]<nums[j]){
LIS[i]=max(LIS[i],1+LIS[j]);
}
}
}
return *max_element(LIS.begin(),LIS.end());
}
};
|
longest increasing subsequence ending at each index
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
//longest increasing subsequence ending at each index
vector<int> LIS(n,1);
for(int i=1;i<n;i++){
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
LIS[i]=max(LIS[i],1+LIS[j]);
}
}
}
return *max_element(LIS.begin(),LIS.end());
}
};
|
Greedy+Binary Search
- 时间复杂度:O(nlogn)
- 空间复杂度:O(n)
746 Min Cost Climbing Stairs
1
2
3
4
5
6
7
8
9
10
11
|
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n=cost.size();
vector<int> dp(n+1,0);
for(int i=2;i<=n;i++){
dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
}
return dp[n];
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n=cost.size();
int prev=0,cur=0,next;
for(int i=2;i<=n;i++){
next=min(cur+cost[i-1],prev+cost[i-2]);
prev=cur;
cur=next;
}
return cur;
}
};
|
139 Word Break
for each prefix, if prefix is in dict and wordbreak(remaining str)=True, then return True, cache result of wordbreak;
instead of checking every single possible prefix right of any length what we’re going to be doing is we’re going to be checking every single word in wordDict as the prefix.
Decision Tree——Cache——DP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
int sLen=s.length();
vector<bool> dp(sLen+1,false);
dp[sLen]=true;
for(int i=sLen-1;i>=0;i--){
for(string word:wordDict){
int wordLen=word.length();
//substr(pos,n)
if(i+wordLen<=sLen && word==s.substr(i,wordLen)){
dp[i]=dp[i+wordLen];
}
if(dp[i]){
break;
}
}
}
return dp[0];
}
};
|
198 House Robber
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==1) return nums[0];
vector<int> dp(n);
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int i=2;i<n;i++){
dp[i]=max(nums[i]+dp[i-2],dp[i-1]);
}
return dp[n-1];
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==1) return nums[0];
int prev=nums[0];
int cur=max(nums[0],nums[1]);
int next;
for(int i=2;i<n;i++){
next=max(nums[i]+prev,cur);
prev=cur;
cur=next;
}
return cur;
}
};
|
213 House Robber II
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==1) return nums[0];
if(n==2) return max(nums[0],nums[1]);
return max(robRange(nums,0,n-2),robRange(nums,1,n-1));
}
int robRange(vector<int>& nums,int left,int right){
int n=nums.size();
vector<int> dp(n);
dp[left]=nums[left];
dp[left+1]=max(nums[left],nums[left+1]);
for(int i=left+2;i<=right;i++){
dp[i]=max(nums[i]+dp[i-2],dp[i-1]);
}
return dp[right];
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==1) return nums[0];
if(n==2) return max(nums[0],nums[1]);
return max(robRange(nums,0,n-2),robRange(nums,1,n-1));
}
int robRange(vector<int>& nums,int left,int right){
int prev=nums[left];
int cur=max(nums[left],nums[left+1]);
int next;
for(int i=left+2;i<=right;i++){
next=max(nums[i]+prev,cur);
prev=cur;
cur=next;
}
return cur;
}
};
|
91 Decode Ways
LINK: FACEBOOK CODING INTERVIEW QUESTION - DECODE WAYS (LeetCode)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Solution {
public:
int numDecodings(string s) {
int len=s.length();
vector<int> dp(len+1);
dp[0]=1;
dp[1]=(s[0]=='0'?0:1);
for(int i=2;i<=len;i++){
int oneDigit=s[i-1]-'0';
int twoDigit=stoi(s.substr(i-2,2));
if(oneDigit!=0) dp[i]+=dp[i-1];
if(twoDigit>=10 && twoDigit<=26) dp[i]+=dp[i-2];
}
return dp[len];
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Solution {
public:
int numDecodings(string s) {
int len=s.length();
vector<int> dp(len+1);
int prev=1;
int cur=(s[0]=='0'?0:1);
for(int i=2;i<=len;i++){
int next=0;
int oneDigit=s[i-1]-'0';
int twoDigit=stoi(s.substr(i-2,2));
if(oneDigit!=0) next+=cur;
if(twoDigit>=10 && twoDigit<=26) next+=prev;
prev=cur;
cur=next;
}
return cur;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Solution {
public:
int numDecodings(string s) {
int len=s.length();
vector<int> dp(len+1);
dp[0]=1;
for(int i=1;i<=len;i++){
if(s[i-1]!='0') dp[i]+=dp[i-1];
if(i>=2){
int twoDigit=stoi(s.substr(i-2,2));
if(twoDigit>=10 && twoDigit<=26) dp[i]+=dp[i-2];
}
}
return dp[len];
}
};
|
55 Jump Game
Dynamic Programming
Greedy
从前往后
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Solution {
public:
bool canJump(vector<int>& nums) {
int n=nums.size();
int rightMost=0;
for(int i=0;i<n;i++){
if(i<=rightMost){
rightMost=max(rightMost,i+nums[i]);
if(rightMost>=n-1){
return true;
}
}
}
return false;
}
};
|
从后往前
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Solution {
public:
bool canJump(vector<int>& nums) {
int n=nums.size();
int goal=n-1;
for(int i=n-1;i>=0;i--){
if(i+nums[i]>=goal){
goal=i;
}
}
return goal==0?true:false;
}
};
|
5 Longest Palindromic Substring
DP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
class Solution {
public:
string longestPalindrome(string s) {
int n=s.length();
if(n<2) return s;
vector<vector<bool>> dp(n,vector<bool>(n,false));
for(int i=0;i<n;i++){
dp[i][i]=true;
}
int begin=0;
int maxLen=1;
for(int L=2;L<=n;L++){
for(int i=0;i<n;i++){
int j=i+L-1;
if(j>=n) break;
if(s[i]==s[j]){
if(j-i<=2){
dp[i][j]=true;
}else{
dp[i][j]=dp[i+1][j-1];
}
}else{
dp[i][j]=false;
}
if(j-i+1>maxLen && dp[i][j]){
begin=i;
maxLen=j-i+1;
}
}
}
return s.substr(begin,maxLen);
}
};
|
- 时间复杂度:O(n^2)
- 空间复杂度:O(n^2)
中心拓展算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
class Solution {
public:
string longestPalindrome(string s) {
int n=s.length();
if(n<=1) return s;
int left=0,right=0;
int len=1;
int maxStart=0;
int maxLen=0;
for(int i=0;i<n;i++){
left=i-1;
right=i+1;
while(left>=0 && s[left]==s[i]){
len+=1;
left--;
}
while(right<n && s[right]==s[i]){
len+=1;
right++;
}
while(left>=0 && right<n && s[left]==s[right]){
len+=2;
left--;
right++;
}
if(len>maxLen){
maxStart=left;
maxLen=len;
}
len=1;
}
return s.substr(maxStart+1,maxLen);
}
};
|
343 整数拆分
递归
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Solution {
public:
int integerBreak(int n) {
if(n==1 || n==2){
return 1;
}
int res=0;
for(int i=1;i<=n;i++){
res=max({res,i*integerBreak(n-i),i*(n-i)});
}
return res;
}
};
|
超出时间限制。
DP
1
2
3
4
5
6
7
8
9
10
11
12
|
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n+1);
for(int i=2;i<=n;i++){
for(int j=1;j<i;j++){
dp[i]=max({dp[i],j*dp[i-j],j*(i-j)});
}
}
return dp[n];
}
};
|
2D DP
1143 Longest Common Subsequence
Buttom-Up1
recursive: if first chars are equal find lcs of remaining of each, else max of: lcs of first and remain of 2nd and lcs of 2nd remain of first, cache result; nested forloop to compute the cache without recursion;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m=text1.length(),n=text2.length();
vector<vector<int>> LCS(m+1,vector<int>(n+1));
// for(int i=0;i<=m;i++){
// LCS[i][n]=0;
// }
// for(int j=0;j<=n;j++){
// LCS[m][j]=0;
// }
for(int i=m-1;i>=0;i--){
for(int j=n-1;j>=0;j--){
if(text1[i]==text2[j]){
LCS[i][j]=1+LCS[i+1][j+1];
}else{
LCS[i][j]=max(LCS[i+1][j],LCS[i][j+1]);
}
}
}
return LCS[0][0];
}
};
|
注意:这里比较的是text1[i]==text2[j]
Buttom-Up2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m=text1.length(),n=text2.length();
vector<vector<int>> LCS(m+1,vector<int>(n+1));
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(text1[i-1]==text2[j-1]){
LCS[i][j]=1+LCS[i-1][j-1];
}else{
LCS[i][j]=max(LCS[i-1][j],LCS[i][j-1]);
}
}
}
return LCS[m][n];
}
};
|
注意:这里比较的是text1[i-1]==text2[j-1]
62 Unique Paths
1
2
3
4
5
6
7
8
9
10
11
12
|
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> dp(m,vector<int>(n,1));
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
dp[i][j]=dp[i][j-1]+dp[i-1][j];
}
}
return dp[m-1][n-1];
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Solution {
public:
int uniquePaths(int m, int n) {
vector<int> pre(n,1),cur(n,1);
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
cur[j]=pre[j]+cur[j-1];
}
pre=cur;
}
return cur[n-1];
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
|
class Solution {
public:
int uniquePaths(int m, int n) {
vector<int> dp(n,1);
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
dp[j]+=dp[j-1];
}
}
return dp[n-1];
}
};
|
97 Interleaving String
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
int len1=s1.length(),len2=s2.length();
if(len1+len2!=s3.length()) return false;
vector<vector<bool>> dp(len1+1,vector<bool>(len2+1,false));
dp[len1][len2]=true;
for(int i=len1;i>=0;i--){
for(int j=len2;j>=0;j--){
if(i<len1 && s1[i]==s3[i+j] && dp[i+1][j]){
dp[i][j]=true;
}
if(j<len2 && s2[j]==s3[i+j] && dp[i][j+1]){
dp[i][j]=true;
}
}
}
return dp[0][0];
}
};
|
1155 Number of Dice Rolls With Target Sum
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Solution {
public:
const int MOD=1e9+7;
int numRollsToTarget(int n, int k, int target) {
//dp[i][j] 扔i枚骰子和为j
vector<vector<int>> dp(n+1,vector<int>(target+1,0));
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=target;j++){
for(int t=1;t<=k;t++){
if(t<=j){
dp[i][j]=(dp[i][j]+dp[i-1][j-t])%MOD;
}
}
}
}
return dp[n][target];
}
};
|
- 时间复杂度:O(n*target*k)
- 空间复杂度:O(n*target)
64 Minimum Path Sum
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m=grid.size();
int n=grid[0].size();
vector<vector<int>> dp(m,vector<int>(n));
dp[0][0]=grid[0][0];
for(int i=1;i<m;i++){
dp[i][0]=dp[i-1][0]+grid[i][0];
}
for(int j=1;j<n;j++){
dp[0][j]=dp[0][j-1]+grid[0][j];
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
}
return dp[m-1][n-1];
}
};
|
801 Minimum Swaps To Make Sequences Increasing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
class Solution {
public:
int minSwap(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size();
vector<vector<int>> dp(n,vector<int>(2));
dp[0][0]=0;
dp[0][1]=1;
//其余未知状态初始化为正无穷
for(int i=1;i<n;i++){
dp[i][0]=dp[i][1]=n+10;
}
for(int i=1;i<n;i++){
if(nums1[i]>nums1[i-1] && nums2[i]>nums2[i-1]){
//都不交换
dp[i][0]=dp[i-1][0];
//都交换
dp[i][1]=dp[i-1][1]+1;
}
if(nums1[i]>nums2[i-1] && nums2[i]>nums1[i-1]){
//当前位置 i 和前一位置 i - 1 只能有其一发生交换
//前一位置交换
dp[i][0]=min(dp[i][0],dp[i-1][1]);
//当前位置交换
dp[i][1]=min(dp[i][1],dp[i-1][0]+1);
}
}
return min(dp[n-1][0],dp[n-1][1]);
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
class Solution {
public:
int minSwap(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size();
vector<vector<int>> dp(2,vector<int>(2));
dp[0][0]=0;
dp[0][1]=1;
for(int i=1;i<n;i++){
int a=n+10,b=n+10;
int prev=(i-1)&1,cur=i&1;
if(nums1[i]>nums1[i-1] && nums2[i]>nums2[i-1]){
//都不交换
a=dp[prev][0];
//都交换
b=dp[prev][1]+1;
}
if(nums1[i]>nums2[i-1] && nums2[i]>nums1[i-1]){
//当前位置 i 和前一位置 i - 1 只能有其一发生交换
//前一位置交换
a=min(a,dp[prev][1]);
//当前位置交换
b=min(b,dp[prev][0]+1);
}
dp[cur][0]=a;
dp[cur][1]=b;
}
return min(dp[(n-1)&1][0],dp[(n-1)&1][1]);
}
};
|
10 Regular Expression Matching
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
class Solution {
public:
bool isMatch(string s, string p) {
int m=s.size();
int n=p.size();
auto matches=[&](int i,int j){
if(i==0) return false;
if(p[j-1]=='.') return true;
return s[i-1]==p[j-1];
};
vector<vector<int>> dp(m+1,vector<int>(n+1));
dp[0][0]=1;
for(int i=0;i<=m;i++){
for(int j=1;j<=n;j++){
if (p[j - 1] == '*') {
dp[i][j] |= dp[i][j - 2];
if (matches(i, j - 1)) {
dp[i][j] |= dp[i - 1][j];
}
}
else {
if (matches(i, j)) {
dp[i][j] |= dp[i - 1][j - 1];
}
}
}
}
return dp[m][n];
}
};
|
115 Distinct Subsequences
940 Distinct Subsequences II
Author
Anjana
LastMod
2022-07-18
License
原创文章,如需转载请注明作者和出处。谢谢!