LeetCode题解-06(分治、动态规划)
目录
LeetCode题解
chap-15:分治
1、不同的二叉搜索树 II【卡特兰数】
class Solution {
public:
vector<TreeNode*> generateTrees(int n) {
return dfs(1,n);
}
vector<TreeNode*> dfs(int l,int r){
if(l>r) return{nullptr};
vector<TreeNode*> res;
for(int i = l;i<=r;i++){
auto left = dfs(l,i-1),right = dfs(i+1,r);
for(auto &l:left){
for(auto &r:right){
auto root = new TreeNode(i);
root->left = l;
root->right = r;
res.push_back(root);
}
}
}
return res;
}
};
2、为运算表达式设计优先级
class Solution {
public:
vector<int> diffWaysToCompute(string ep) {
vector<int> ans;
for(int i=0;i<ep.size();i++){
if(ep[i]<'0'){
for(auto &a:diffWaysToCompute(ep.substr(0,i)))
for(auto &b:diffWaysToCompute(ep.substr(i+1)))
ans.push_back(ep[i]=='+'?a+b:ep[i]=='-'?a-b:a*b);
}
}
return ans.empty()?vector<int>{stoi(ep)}:ans;
}
};
3、从前序与中序遍历序列构造二叉树
class Solution {
public:
unordered_map<int,int> hash;
TreeNode* buildTree(vector<int>& pre, vector<int>& in) {
for(int i=0;i<pre.size();i++) hash[in[i]]=i;
return dfs(pre,in,0,pre.size()-1,0,in.size()-1);
}
TreeNode* dfs(vector<int>&pre, vector<int>&in, int pl,int pr,int il,int ir){
if(pl>pr) return nullptr;
auto root = new TreeNode(pre[pl]);
int i = hash[root->val];
root->left = dfs(pre,in,pl+1,i-il+pl,il,i-1);
root->right = dfs(pre,in,i-il+pl+1,pr,i+1,ir);
return root;
}
};
4、从中序与后序遍历序列构造二叉树
class Solution {
public:
unordered_map<int, int> pos;
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
for (int i = 0; i < inorder.size(); i ++ ) pos[inorder[i]] = i;
return build(inorder, postorder, 0, inorder.size() - 1, 0, postorder.size() - 1);
}
TreeNode* build(vector<int>& inorder, vector<int>& postorder, int il, int ir, int pl, int pr) {
if (il > ir) return NULL;
auto root = new TreeNode(postorder[pr]);
int k = pos[root->val];
root->left = build(inorder, postorder, il, k - 1, pl, pl + k - 1 - il);
root->right = build(inorder, postorder, k + 1, ir, pl + k - 1 - il + 1, pr - 1);
return root;
}
};
5、将有序数组转换为二叉搜索树
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
return dfs(0,nums.size()-1,nums);
}
TreeNode* dfs(int l, int r, vector<int>&nums){
if(l>r) return nullptr;
int mid=l+r>>1;
auto root = new TreeNode(nums[mid]);
root->left = dfs(l,mid-1,nums);
root->right = dfs(mid+1,r,nums);
return root;
}
};
6、有序链表转换二叉搜索树
class Solution {
public:
TreeNode* sortedListToBST(ListNode* head) {
if(head == nullptr) return nullptr;
int n=0;
for(auto p = head;p;p = p->next) n++;
if(n == 1) return new TreeNode(head->val);
auto cur = head;
for(int i =0;i<n/2-1;i++){
cur = cur->next;
}
auto t = new TreeNode(cur->next->val);
t->right = sortedListToBST(cur->next->next);
cur->next = nullptr;
t->left = sortedListToBST(head);
return t;
}
};
[Go Back~](# LeetCode题解)
chap-16:动态规划
section16-1: 背包问题
1、01背包 分割等和子集
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum=accumulate(nums.begin(),nums.end(),0);
if(sum%2) return false;
sum/=2; vector<bool>f(sum+1,false); f[0]=true;
for(auto &n:nums){
for(int i=sum;i>=n;i--)
f[i] = f[i]|f[i-n];
if(f[sum]) return true;
}
return f[sum];
}
};
2、01背包 目标和 【×】
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int offset=accumulate(nums.begin(),nums.end(),0);
offset = max(abs(target), offset);
int n=nums.size();
vector<vector<int>> f(n+1,vector<int>(2*offset+1,0));
f[0][offset+0]=1;
for(int i=1;i<=n;i++){
for(int j=offset;j>=-offset;j--){
if(j-nums[i-1]>=-offset)
f[i][j+offset] += f[i-1][j-nums[i-1]+offset] ;
if(j+nums[i-1]<=offset)
f[i][j+offset] += f[i-1][j+nums[i-1]+offset] ;
}
}
return f[n][target+offset];
}
};
3、完全背包 完全平方数
class Solution {
public:
int numSquares(int n) {
vector<int> f(n+1,INT_MAX); f[0]=0;
for(int i=1;i*i<=n;i++){
int t = i*i;
for(int j=t;j<=n;j++)
f[j] = min(f[j], f[j-t]+1);
}
return f[n];
}
};
4、完全背包 零钱兑换
class Solution {
public:
int coinChange(vector<int>& coins, int m) {
int n = coins.size();
sort(coins.begin(),coins.end());
vector<int> f(m+1,0x3f3f3f3f);
f[0] = 0;
for(int i = 1;i<=m;i++){
for(int j = n-1;j>=0;j--){
if(i - coins[j] >= 0)
f[i] = min(f[i - coins[j]] + 1,f[i]);
}
}
return f[m] == 0x3f3f3f3f ? -1 : f[m];
}
};
5、完全背包 零钱兑换 II
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> f(amount+1,0);
f[0]=1;
for(auto &coin : coins){
for(int i=coin;i<=amount;i++)
f[i] += f[i-coin];
}
return f[amount];
}
};
6、二维背包 一和零
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>>f(m+1,vector<int>(n+1,0));
for(auto &s:strs){
int cnt0=0,cnt1=0;
for(auto &c:s) if(c=='0') cnt0++; else cnt1++;
for(int i=m;i>=cnt0;i--)
for(int j=n;j>=cnt1;j--)
f[i][j] = max(f[i][j], f[i-cnt0][j-cnt1]+1);
}
return f[m][n];
}
};
7、求方案数 数位成本和为目标值的最大数字
class Solution {
public:
string largestNumber(vector<int>& cost, int target) {
vector<int> f(target+1,INT_MIN);
f[0]=0;
for(int i=0;i<cost.size();i++)
for(int j=cost[i];j<=target;j++)
f[j] = max(f[j], f[j-cost[i]]+1);
if(f[target]<0) return "0";
string ans;
for (int i = 8, j = target; i >= 0; i--) {
while (j >= cost[i] && f[j] == f[j - cost[i]] + 1) {
ans += to_string(i + 1);
j -= cost[i];
}
}
return ans;
}
};
[Go Back~](# LeetCode题解)
section16-2: LIS模型
1、最长递增子序列
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> dp(nums.size(),1); // O(n^2)
int res = 1;
for(int i= 1;i<nums.size();i++){
for(int j = 0;j<i;j++){
if(nums[i]>nums[j])
dp[i] = max(dp[i],dp[j]+1);
}
res = max(dp[i], res);
}
return res;
}
};
// O(nlog(n))
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size(), len=1;
vector<int> f(n+1,0);
f[len]=nums[0];
for(int i=1;i<=n;i++){
int l=1, r=len;
while(l<=r){
int mid=l+r>>1;
if(f[mid] < nums[i-1]) l = mid+1;
else r=mid-1;
}
if(l>len) len++; f[l]=nums[i-1];
}
return len;
}
};
2、俄罗斯套娃信封问题
class Solution {
public:
int maxEnvelopes(vector<vector<int>>& envelopes) {
int n = envelopes.size();
sort(envelopes.begin(),envelopes.end());
vector<int> f(n+1,1);
int ans=0;
for(int i=1;i<=n;i++){
int w=envelopes[i-1][0], h=envelopes[i-1][1];
for(int j=1;j<i;j++){
if(envelopes[j-1][0]<w && envelopes[j-1][1]<h)
f[i] = max(f[i], f[j]+1);
}
ans = max(ans,f[i]);
}
return ans;
}
};
3、最大整除子集
class Solution {
public:
vector<int> largestDivisibleSubset(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<int> f(nums.size()+1,0);
int t=0;
for(int i=1;i<=nums.size();i++){
f[i]=1;
for(int j=1;j<i;j++)
if(nums[i-1]%nums[j-1] == 0)
f[i] = max(f[i],f[j]+1);
t=max(t,f[i]);
}
vector<int> ans;
for(int j=nums.size();j>=1;j--){
if(t == f[j]){
if(ans.empty()) t--,ans.push_back(nums[j-1]);
else if(ans.back() % nums[j-1] == 0)
t--,ans.push_back(nums[j-1]);
}
}
return ans;
}
};
4、无矛盾的最佳球队
class Solution {
public:
int bestTeamScore(vector<int>& scores, vector<int>& ages) {
int n=scores.size(); vector<int> rank(n);
for(int i=0;i<n;i++) rank[i]=i;
sort(rank.begin(), rank.end(), [&](int &i, int &j){
if(scores[i]!=scores[j]) return scores[i]<scores[j];
else return ages[i]<ages[j];
});
vector<int> f(n+1); int ans=0;
for (int i = 0; i < n; i++) {
f[i] = scores[rank[i]];
for (int j = 0; j < i; j++)
if (ages[rank[j]] <= ages[rank[i]])
f[i] = max(f[i], f[j] + scores[rank[i]]);
ans = max(ans, f[i]);
}
return ans;
}
};
5、堆叠长方体的最大高度
class Solution {
public:
int maxHeight(vector<vector<int>>& cuboids) {
for(auto &cuboid:cuboids){
sort(cuboid.begin(),cuboid.end());
}
sort(cuboids.begin(),cuboids.end());
vector<int> f(cuboids.size(),0);
int ans=0;
for(int i=0;i<cuboids.size();i++){
f[i]=cuboids[i][2];
for(int j=0;j<i;j++)
if(cuboids[j][1]<=cuboids[i][1] && cuboids[j][2]<=cuboids[i][2])
f[i] = max(f[i],f[j]+cuboids[i][2]);
ans=max(ans,f[i]);
}
return ans;
}
};
[Go Back~](# LeetCode题解)
section16-3: 线性DP
1、最大子数组和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int sum = 0,ans = -0x3f3f3f3f;
for(auto &item:nums){
sum += item;
ans = max(sum,ans);
if(sum < 0) sum = 0;
}
return ans;
}
};
2、不同路径
class Solution {
public:
int uniquePaths(int m, int n) {
vector<int> f(n+1,0);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++){
if(i==1&&j==1) f[j]=1;
else f[j] = f[j] + f[j-1];
}
return f[n];
}
};
3、不同路径 II
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& w) {
int n=w.size(), m=w[0].size();
if(w[0][0] || w[n-1][m-1]) return 0;
vector<vector<int>> f(n+1,vector<int>(m+1,0));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(i==1 && j==1) f[i][j]=1;
else if(!w[i-1][j-1]) f[i][j]=f[i-1][j]+f[i][j-1];
return f[n][m];
}
};
4、最小路径和
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int n=grid.size(), m=grid[0].size();
vector<int>f(m+1,0x3f3f3f3f);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
if(i==1 && j==1) f[j]=grid[i-1][j-1];
else f[j] = min(f[j], f[j-1]) + grid[i-1][j-1];
}
return f[m];
}
};
5、爬楼梯
class Solution {
public:
int climbStairs(int n) {
vector<int> f(n+1); f[0]=1, f[1]=1;
for(int i=2;i<=n;i++)
f[i] = f[i-1]+f[i-2];
return f[n];
}
};
class Solution {
public:
int climbStairs(int n) {
int a=1, b=1, c;
for(int i=2;i<=n;i++){
c = a+b; a = b; b = c;
}
return b;
}
};
6、编辑距离 【×】
class Solution {
public:
int minDistance(string word1, string word2) {
int n=word1.size(), m=word2.size();
word1 = ' '+word1;
word2 = ' '+word2;
vector<vector<int>> f(n+1,vector<int>(m+1,0x3f3f3f));
for (int i = 0; i <= n; i ++ ) f[i][0] = i;
for (int i = 1; i <= m; i ++ ) f[0][i] = i;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(word2[j] == word1[i])
f[i][j] = min(f[i-1][j-1], f[i][j]);
else
f[i][j] = min(f[i-1][j-1]+1, min(f[i-1][j]+1, f[i][j-1]+1));
}
}
return f[n][m];
}
};
7、解码方法
class Solution {
public:
int numDecodings(string s) {
int n=s.size();
vector<int> f(n+1,0);
s = ' '+s;
f[0]=1;
for(int i=1;i<=n;i++){
if(i==1) {if(s[i] != '0') f[i]=1;}
else {
string t; t+=s[i-1]; t+=s[i];
int a = stoi(t);
if(s[i] != '0'){
f[i] = f[i-1];
if(a>=10 && a<=26) f[i] = f[i]+f[i-2];
}else{
if(a == 10 || a == 20)
f[i] = f[i-2];
}
}
}
return f[n];
}
};
8、不同的二叉搜索树
class Solution {
public:
int numTrees(int n) {
vector<int>f(n+1,0);
f[0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
f[i] += f[i-j]*f[j-1];
return f[n];
}
};
9、交错字符串
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
int n1 = s1.size(), n2 = s2.size(), n = s3.size();
if((n1+n2) != n) return false;
vector<vector<bool>> f(n1+1,vector<bool>(n2+1, false));
s1 = ' '+s1; s2 = ' '+s2; s3 = ' '+s3;
for(int j=0;j<=n1;j++)
for(int i=0;i<=n2;i++){
if(!i && !j) f[j][i] = 1;
else{
if(j && s1[j] == s3[i+j]) f[j][i] = f[j-1][i];
if(i && s2[i] == s3[i+j]) f[j][i] = f[j][i] || f[j][i-1];
}
}
return f[n1][n2];
}
};
10、不同的子序列
class Solution {
public:
int numDistinct(string s, string t) {
int n=s.size(),m=t.size();
s = ' '+s; t = ' '+t;
vector<vector<unsigned long long>>f(m+1,vector<unsigned long long>(n+1,0));
for(int i=0;i<=n;i++) f[0][i]=1;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++){
if(s[j] != t[i]) f[i][j] = f[i][j-1];
else f[i][j] = f[i-1][j-1]+f[i][j-1];
}
return f[m][n];
}
};
11、杨辉三角
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> ans;
for(int i=1;i<=numRows;i++){
if(ans.empty()) ans.push_back({1});
else{
vector<int> t; t.push_back(1);
for(int j=2;j<=i;j++){
if(j>ans.back().size()) t.push_back(1);
else{
t.push_back(ans.back()[j-2]+ans.back()[j-1]);
}
}
ans.push_back(t);
}
}
return ans;
}
};
12、杨辉三角 II
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<int> ans(rowIndex+1,0);
for(int i=0;i<=rowIndex;i++){
for(int j=i;j>=0;j--){
if(!j) ans[j] = 1;
else{
if(j < i) ans[j] = ans[j-1] + ans[j];
else ans[j] = ans[j-1] + 0;
}
}
}
return ans;
}
};
13、三角形最小路径和
class Solution {
public:
int minimumTotal(vector<vector<int>>& dp) {
for(int i = dp.size() - 2;i>=0;i--){
for(int j = 0;j<dp[i].size();j++){
dp[i][j] += min(dp[i+1][j],dp[i+1][j+1]);
}
}
return dp[0][0];
}
};
14、分割回文串
class Solution {
public:
vector<vector<bool>> f;
vector<vector<string>> res;
vector<vector<string>> partition(string s) {
int n=s.size();
f = vector<vector<bool>>(n,vector<bool>(n,false));
f[0][0]=1;
for(int i=1;i<n;i++){
f[i][i]=1;
if(s[i-1] == s[i]) f[i-1][i]=1;
}
for(int len=2;len<n;len++)
for(int i=0;i+len<n;i++){
f[i][i+len] = f[i+1][i+len-1] && (s[i]==s[i+len]);
}
vector<string> path;
dfs(s,0,path);
return res;
}
void dfs(string&s, int u,vector<string> path){
if(u == s.size()) res.push_back(path);
else{
for(int i=u;i<s.size();i++){
if(f[u][i]){
path.push_back(s.substr(u,i-u+1));
dfs(s,i+1,path);
path.pop_back();
}
}
}
}
};
15、分割回文串 II【×】
class Solution {
public:
int minCut(string s) {
int n = s.size();
vector<vector<bool>>f(n,vector<bool>(n,false));
f[0][0]=1;
for(int i=1;i<n;i++){
f[i][i]=1, f[i-1][i]=(s[i-1]==s[i]);
}
for(int len=2;len<n;len++){
for(int j=0;j+len<n;j++)
f[j][j+len] = f[j+1][j+len-1] && (s[j] == s[len+j]);
}
vector<int> dp(n+1,INT_MAX);
dp[0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++)
if(f[j][i-1]) dp[i] = min(dp[i], dp[j]+1);
}
return max(0,dp[n]-1);
}
};
16、地下城游戏【×】
class Solution {
public:
int calculateMinimumHP(vector<vector<int>>& dungeon) {
int n=dungeon.size(), m=dungeon[0].size();
vector<vector<int>> f(n+1,vector<int>(m+1,0x3f3f3f));
f[n][m-1]=1, f[n-1][m]=1;
for(int i=n-1;i>=0;i--){
for(int j=m-1;j>=0;j--){
f[i][j] = max(1,min(f[i+1][j],f[i][j+1])-dungeon[i][j]);
}
}
return f[0][0];
}
};
17、最大正方形
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
int n = matrix.size(), m = matrix[0].size();
vector<vector<int>> f(n+1,vector<int>(m+1));
int res = 0;
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
if(matrix[i-1][j-1] == '0') f[i][j] = 0;
else{
f[i][j] = min(f[i-1][j-1],min(f[i-1][j],f[i][j-1])) + 1;
res = max(res,f[i][j]);
}
}
}
return res * res;
}
};
18、摆动序列
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int n=nums.size();
vector<int> f1(n,0); //上升序列
vector<int> f0(n,0); //下沉序列
f0[0]=f1[0]=1;
for(int i=1;i<n;i++){
if(nums[i]>nums[i-1]){
f1[i]=f0[i-1]+1;
f0[i]=f0[i-1];
}else if(nums[i]<nums[i-1]){
f0[i]=f1[i-1]+1;
f1[i]=f1[i-1];
}else f0[i]=f0[i-1], f1[i]=f1[i-1];
}
return max(f0[n-1],f1[n-1]);
}
};
19、斐波那契数
class Solution {
public:
int fib(int n) {
if(!n) return 0;
vector<int> f(n+1,0);
f[0]=0, f[1]=1;
for(int i=2;i<=n;i++) f[i]=f[i-1]+f[i-2];
return f[n];
}
};
class Solution {
public:
int fib(int n) {
if(!n) return 0;
int c=0, a=0, b=1;
for(int i=2;i<=n;i++) {
c=a+b;
a = b;
b = c;
}
return b;
}
};
20、自由之路【×】
class Solution {
public:
int findRotateSteps(string ring, string key) {
int n=ring.size(), m=key.size();
vector<vector<int>> f(m,vector<int>(n,0x3f3f3f));
for(int i=0;i<n;i++){
if(ring[i] == key[0])
f[0][i] = min(i,n-i)+1;
}
for(int i=1;i<m;i++){
for(int j=0;j<n;j++){
if(key[i] == ring[j]){
for(int k=0;k<n;k++){
if(key[i-1] == ring[k]){
int cost = f[i-1][k] + min((j-k+n)%n, (k-j+n)%n) +1;
f[i][j] = min(f[i][j], cost);
}
}
}
}
}
int ans=INT_MAX;
for(int i=0;i<n;i++) ans=min(ans, f[m-1][i]);
return ans;
}
};
21、掷骰子的N种方法
class Solution {
public:
int numRollsToTarget(int n, int k, int target) {
const int mod = 1e9 + 7;
vector<vector<int>>f(n+1,vector<int>(target+1,0));
f[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
for(int t=j;t<=target;t++)
f[i][t] = (f[i][t] + f[i-1][t-j])%mod;
}
}
return f[n][target];
}
};
22、带限制的子序列和 【单调队列】
class Solution {
public:
int constrainedSubsetSum(vector<int>& nums, int k) {
int n=nums.size();
vector<int> f(n,0);
f[0]=nums[0];
int ans=nums[0];
deque<int> q;
q.push_back(0);
for(int i=1;i<n;i++){
while(q.size() && i-q.front()>k) q.pop_front();
f[i] = max(0, f[q.front()]) + nums[i];
ans = max(f[i], ans);
while(q.size() && f[i] >= f[q.back()]) q.pop_back();
q.push_back(i);
}
return ans;
}
};
23、跳跃游戏 VI
class Solution {
public:
int maxResult(vector<int>& nums, int k) {
int n=nums.size();
vector<int> f(n,0); f[0]=nums[0];
deque<int> q; q.push_back(0);
for(int i=1;i<n;i++){
while(q.size() && i - q.front()>k) q.pop_front();
f[i] = f[q.front()] + nums[i];
while(q.size() && f[i] >= f[q.back()]) q.pop_back();
q.push_back(i);
}
return f[n-1];
}
};
[Go Back~](# LeetCode题解)
section16-4: 杂选热点DP问题
1、打家劫舍
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
vector<int> f(n+1,0);
for(int i=1;i<=n;i++){
if(i==1) f[i] = max(f[i-1], nums[i-1]);
else f[i] = max(f[i-1], f[i-2]+nums[i-1]);
}
return f[n];
}
};
2、打家劫舍 II
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size(), ans=0;
vector<int> f(n+1,0);
for(int i=n-1;i>=0;i--){
// 第一个不取,最后一个取
if(i==n-1) f[i] = nums[i];
else if(i == 0) f[i] = f[i+1];
else f[i] = max(f[i+1], f[i+2]+nums[i]);
}
ans = max(ans, f[0]);
f = vector<int>(n+1,0);
for(int i=1;i<=n;i++){
// 第一个取,最后一个不取
if(i==1) f[i] = nums[i-1];
else if(i == n) f[i] = f[i-1];
else f[i] = max(f[i-1], f[i-2]+nums[i-1]);
}
ans = max(ans,f[n]);
return ans;
}
};
3、摘樱桃 【×】
class Solution {
public:
int cherryPickup(vector<vector<int>>& grid) {
int n=grid.size();
vector<vector<vector<int>>> f(2*n,vector<vector<int>>(n,vector<int>(n,-0x3f3f3f)));
f[0][0][0] = grid[0][0];
for(int k=1;k<=2*n-2;k++){
for(int i1=0;i1<n;i1++){
for(int i2=0;i2<n;i2++){
int j1 = k-i1, j2 = k-i2;
if (j1 < 0 || j1 >= n || j2 < 0 || j2 >= n) continue; //越界
if(grid[i1][j1]==-1 || grid[i2][j2] == -1) continue;
int t = grid[i1][j1]; //取得该格子
if (i1 != i2) t += grid[i2][j2]; //没有重合
int &x = f[k][i1][i2];
x = max(x, f[k - 1][i1][i2] + t);
if(i1) x = max(x, f[k-1][i1-1][i2] + t);
if(i2) x = max(x, f[k-1][i1][i2-1] + t);
if(i1 && i2) x = max(x, f[k-1][i1-1][i2-1] + t);
}
}
}
return max(0,f[2*n-2][n-1][n-1]);
}
};
4、摘樱桃 II 【数字三角形dp】
class Solution {
public:
int cherryPickup(vector<vector<int>>& grid) {
int n = grid.size(), m = grid[0].size();
vector<vector<vector<int>>> f(n, vector<vector<int>> (m, vector<int> (m, -1)));
f[0][0][m - 1] = grid[0][0] + grid[0][m - 1]; //开始状态
int res = 0;
for (int k = 1; k < n; k ++) //从第二行开始循环
for (int i = 0; i < m; i ++)
for (int j = 0; j < m; j ++)
for (int a = i - 1; a <= i + 1; a ++) // 可能情况枚举
for (int b = j - 1; b <= j + 1; b ++)
{
if (a < 0 || a >= m || b < 0 || b >= m) continue; //越界
int t = f[k - 1][a][b];
if (t < 0) continue; //不合法
if (i == j) f[k][i][j] = max(f[k][i][j], t + grid[k][i]); //重合时只算一次分值
else f[k][i][j] = max(f[k][i][j], t + grid[k][i] + grid[k][j]);
res = max(res, f[k][i][j]);
}
return res;
}
};
5、买卖股票的最佳时机 【贪心】
class Solution {
public:
int maxProfit(vector<int>& prices) {
int minp = prices[0], ans = 0;
for(int i=1;i<prices.size();i++){
if(prices[i] <= minp)
minp = prices[i];
else
ans = max(ans,prices[i] - minp);
}
return ans;
}
};
6、买卖股票的最佳时机 II 【状态机】
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
int f[n][2]; f[0][0] = 0, f[0][1] = -prices[0];
for(int i=1;i<n;i++){
f[i][0] = max(f[i-1][0], f[i-1][1]+prices[i]);
f[i][1] = max(f[i-1][1], f[i-1][0]-prices[i]);
}
return f[n-1][0];
}
};
// 空间优化
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size(), f = 0, g = -prices[0];
for(int i=1;i<n;i++){
int last_f = f, last_g = g;
f = max(last_f, last_g+prices[i]);
g = max(last_g, last_f-prices[i]);
}
return f;
}
};
7、买卖股票的最佳时机 III
// 状态机
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size(); int f[3][n+1][2];
memset(f,-0x3f,sizeof f);
for(int i=0;i<=n;i++) f[0][i][0] = 0;
for(int j=1;j<=n;j++){
for(int i=1;i<=2;i++){
f[i][j][0] = max(f[i][j-1][0], f[i][j-1][1]+prices[j-1]);
f[i][j][1] = max(f[i][j-1][1], f[i-1][j-1][0]-prices[j-1]);
}
}
int ans=0;
for(int k=0;k<=2;k++) ans = max(ans, f[k][n][0]);
return ans;
}
};
// 前后缀分解
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size(); int f[n], g[n];
memset(f,0,sizeof f); memset(g,0,sizeof g);
for(int i=1,minp=prices[0];i<n;i++){
minp = min(minp, prices[i]);
f[i] = max(f[i-1], prices[i]-minp);
}
for(int i=n-2,maxp=prices[n-1];i>=0;i--){
maxp = max(maxp, prices[i]);
g[i] = max(g[i+1], maxp-prices[i]);
}
int ans=0;
for(int i=0;i<n;i++) ans = max(ans, f[i]+g[i]);
return ans;
}
};
8、买卖股票的最佳时机 IV 【状态机】
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n=prices.size(); int f[k+1][n+1][2];
memset(f,-0x3f,sizeof f);
for(int i=0;i<=n;i++) f[0][i][0] = 0;
for(int j=1;j<=n;j++){
for(int i=1;i<=k;i++){
f[i][j][0] = max(f[i][j-1][0], f[i][j-1][1]+prices[j-1]);
f[i][j][1] = max(f[i][j-1][1], f[i-1][j-1][0]-prices[j-1]);
}
}
int ans=0;
for(int t=0;t<=k;t++) ans = max(ans, f[t][n][0]);
return ans;
}
};
9、最佳买卖股票时机含冷冻期【状态机】
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
vector<int> f(n,0), g(n,0);// f为卖出状态, g为买入状态
f[0] = 0, g[0]=-prices[0];
for(int i=1;i<n;i++){
f[i] = max(f[i-1], g[i-1]+prices[i]);
if(i!=1) g[i] = max(f[i-2]-prices[i], g[i-1]);
else g[i] = max(g[i-1], -prices[i]);
}
return f[n-1];
}
};
10、买卖股票的最佳时机含手续费【状态机】
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int n=prices.size();
vector<int> f(n,0), g(n,0);
f[0]=0, g[0]=-prices[0];
for(int i=1;i<n;i++){
f[i] = max(f[i-1], g[i-1]+prices[i]-fee);
g[i] = max(g[i-1], f[i-1]-prices[i]);
}
return f[n-1];
}
};
11、正则表达式匹配 【×】
class Solution {
public:
bool isMatch(string s, string p) {
int n=s.size(), m=p.size();
s = ' '+s, p = ' '+p;
vector<vector<bool>> f(n+1,vector<bool>(m+1,false));
f[0][0]=true;
for(int i=0;i<=n;i++){
for(int j=1;j<=m;j++){
if(j+1<=m && p[j+1] == '*')continue;
if(p[j] == '*'){
f[i][j] = f[i][j-2] || i && f[i - 1][j] && (s[i] == p[j - 1] || p[j - 1] == '.');
}else if(i && p[j] != '*')
f[i][j] = f[i-1][j-1] && (s[i]==p[j] || p[j]=='.');
}
}
return f[n][m];
}
};
12、通配符匹配
class Solution {
public:
bool isMatch(string s, string p) {
int n=s.size(), m=p.size();
s = ' '+s, p = ' '+p;
vector<vector<bool>> f(n+1,vector<bool>(m+1,false));
f[0][0]=true;
for(int i=0;i<=n;i++){
for(int j=1;j<=m;j++){
if(p[j]=='*') f[i][j] = f[i][j-1] || i && f[i-1][j];
else f[i][j] = i && (s[i]==p[j] || p[j]=='?') && f[i-1][j-1];
}
}
return f[n][m];
}
};
[Go Back~](# LeetCode题解)
23、跳跃游戏 VI
class Solution {
public:
int maxResult(vector<int>& nums, int k) {
int n=nums.size();
vector<int> f(n,0); f[0]=nums[0];
deque<int> q; q.push_back(0);
for(int i=1;i<n;i++){
while(q.size() && i - q.front()>k) q.pop_front();
f[i] = f[q.front()] + nums[i];
while(q.size() && f[i] >= f[q.back()]) q.pop_back();
q.push_back(i);
}
return f[n-1];
}
};
[Go Back~](# LeetCode题解)
section16-5: 区间DP
1、戳气球
class Solution {
public:
int maxCoins(vector<int>& nums) {
int n=nums.size();
nums.insert(nums.begin(),1); nums.push_back(1);
vector<vector<int>> f(n+2,vector<int>(n+2,0));
for(int len=1;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int k=i;k<=j;k++){
f[i][j] = max(f[i][j], f[i][k-1]+f[k+1][j]+nums[i-1]*nums[k]*nums[j+1]);
}
}
}
return f[1][n];
}
};
2、猜数字大小 II
class Solution {
public:
int getMoneyAmount(int n) {
vector<vector<int>>f(n+2,vector<int>(n+2,0));
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
f[i][j] = 0x3f3f3f3f;
for(int k=i;k<=j;k++){
f[i][j] = min(f[i][j], max(f[i][k-1], f[k+1][j])+k);
}
}
}
return f[1][n];
}
};
3、预测赢家
1、我们可以简化算法 1 中的状态表示,我们设\(f(i,j)\)表示闭区间$ [i, j] \(下,**先手玩家与后手玩家的得分差距的最大值**。 2、初始时,\)f(i,i)=nums[i]\(。 3、转移时,\)f(i,j)=max(−f(i+1,j)+nums[i],−f(i,j−1)+nums[j])\(。这里的含义为,因为此时是先手玩家,被转移的区间就是后手玩家的得分,所以需要 取相反数 然后转移。 4、最后我们只需要判断\) f(i,j)$是否大于等于 0。
class Solution {
public:
bool PredictTheWinner(vector<int>& nums) {
int n=nums.size();
vector<vector<int>> f(n+1, vector<int>(n+1,0));
for(int len=1;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
if(len==1) f[i][j] = nums[i-1];
else{
f[i][j] = max(-f[i+1][j]+nums[i-1], -f[i][j-1]+nums[j-1]);
}
}
}
return f[1][n]>=0;
}
};
4、最长回文子序列
class Solution {
public:
int longestPalindromeSubseq(string s) {
int n=s.size();
vector<vector<int>> f(n+2,vector<int>(n+2,0));
f[0][0]=1;
for(int i=1;i<=n;i++) f[i][i]=1;
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
if(s[i-1] == s[j-1]) f[i][j] = max(f[i][j], 2+f[i+1][j-1]);
else f[i][j] = max(f[i+1][j], f[i][j-1]);
}
}
return f[1][n];
}
};
5、统计不同回文子序列 【×】区间dp+双端队列
class Solution {
public:
int countPalindromicSubsequences(string s) {
int n=s.size(); const int mod=1e9+7;
vector<vector<int>> f(n+2,vector<int>(n+2,1));
f[0][0] = 1;
for(int i=1;i<=n;i++) f[i][i]++;
for(int len=2;len<=n;len++){
deque<int> q[4];
for(int i=1;i<=n;i++){
q[s[i-1]-'a'].push_back(i);
int j=i-len+1;
if(j>=1){
for(int k=0;k<4;k++){
while(q[k].size() && q[k].front() < j) q[k].pop_front();
if(q[k].size()){
f[j][i] ++ ;
int l = q[k].front(), r = q[k].back();
if (l < r)
f[j][i] = (f[j][i] + f[l + 1][r - 1]) % mod;
}
}
}
}
}
return (f[1][n]+mod-1)%mod;
}
};
6、石子游戏 【思路同题3】
class Solution {
public:
bool stoneGame(vector<int>& piles) {
int n=piles.size();
vector<vector<int>>f(n+2,vector<int>(n+2,0));
for(int i=1;i<=n;i++) f[i][i]=piles[i-1];
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
f[i][j] = max(-f[i+1][j]+piles[i-1], -f[i][j-1]+piles[j-1]);
}
}
return f[1][n]>0;
}
};
7、石子游戏 VII
转移:\(f(i,j)=max(sum(i+1,j)−f(i+1,j),sum(i,j−1)−f(i,j−1))\)
class Solution {
public:
int stoneGameVII(vector<int>& stones) {
int n=stones.size();
vector<int> sum(n + 1, 0);
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + stones[i - 1];
vector<vector<int>> f(n+2,vector<int>(n+2,-0x3f3f3f));
for (int i = 1; i <= n; i++) f[i][i] = 0;
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
f[i][j] = max(sum[j]-sum[i]-f[i+1][j], sum[j-1]-sum[i-1]-f[i][j-1]);
}
}
return f[1][n];
}
};
[Go Back~](# LeetCode题解)
section16-6: 记忆化搜索
1、【树形dp】打家劫舍 III
class Solution {
public:
int rob(TreeNode* root) {
auto f = dfs(root);
return max(f[0],f[1]);
}
vector<int> dfs(TreeNode* root){
if(!root) return {0,0};
auto x = dfs(root->left), y = dfs(root->right);
return {max(x[0],x[1]) + max(y[0],y[1]) , (x[0] + y[0] + root->val)};
}
};
class Solution {
public:
unordered_map<TreeNode*, unordered_map<int,int>> hash;
int rob(TreeNode* root) {
dfs(root);
return max(hash[root][0],hash[root][1]);
}
void dfs(TreeNode*root){
if(!root) return;
dfs(root->left), dfs(root->right);
hash[root][0] = max(hash[root->left][0], hash[root->left][1]) + max(hash[root->right][0], hash[root->right][1]);
hash[root][1] = root->val + hash[root->left][0] + hash[root->right][0];
}
};
2、分发糖果
class Solution {
public:
int candy(vector<int>& ratings) {
// 贪心
int n=ratings.size();
vector<int>f(n,1);
for(int i=0;i<n;i++) if(i && ratings[i-1]<ratings[i]) f[i]=f[i-1]+1;
for(int i=n-1;~i;i--) if(i+1 != n && ratings[i+1] < ratings[i]) f[i]=max(f[i+1]+1,f[i]);
return accumulate(f.begin(),f.end(),0);
}
};
class Solution {
public:
vector<int> f;
int n;
int candy(vector<int>& ratings) {
// 记忆搜索
n=ratings.size();
f.resize(n,-1);
int ans=0;
for(int i=0;i<n;i++)
ans+=dfs(ratings,i);
return ans;
}
int dfs(vector<int>&ratings, int i){
if(f[i]!=-1) return f[i];
f[i]=1;
if(i+1<n && ratings[i+1]<ratings[i])
f[i] = max(f[i],dfs(ratings,i+1)+1);
if(i-1>=0 && ratings[i-1]<ratings[i])
f[i] = max(f[i],dfs(ratings,i-1)+1);
return f[i];
}
};
3、矩阵中的最长递增路径 【对应-滑雪acwing】
class Solution {
public:
int dx[4]={-1,0,1,0}, dy[4]={0,-1,0,1};
vector<vector<int>>f;
int n,m;
int longestIncreasingPath(vector<vector<int>>& matrix) {
n=matrix.size(), m=matrix[0].size();
f=vector<vector<int>>(n,vector<int>(m,-1));
int ans=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
ans=max(ans,dfs(matrix,i,j));
return ans;
}
int dfs(vector<vector<int>>&matrix, int i, int j){
if(f[i][j] != -1) return f[i][j];
f[i][j]=1;
for(int k=0;k<4;k++){
int x=dx[k]+i, y=dy[k]+j;
if(x>=0 && x<n && y>=0 && y<m && matrix[i][j]<matrix[x][y]){
f[i][j] = max(f[i][j], 1+dfs(matrix,x,y));
}
}
return f[i][j];
}
};
4、我能赢吗 【×】
class Solution {
public:
vector<int> f;
int n;
bool canIWin(int m, int total) {
n=m;
if((n+1)*n < 2*total) return false;
if(!total) return true;
f.resize(1<<(n+1),-1);
return dfs(0,total);
}
bool dfs(int u, int t){
if(f[u]!=-1) return f[u];
if(t<=0) return f[u]=false;
for(int i=1;i<=n;i++){
if(!(u & 1<<i)){
if(!dfs(u+(1<<i), t-i))
return f[u]=true;
}
}
return f[u]=false;
}
};
5、猫和老鼠
class Solution {
public:
int n;
vector<vector<vector<int>>> f;
vector<vector<int>> g;
int dfs(int k,int i,int j){
int &v=f[k][i][j];
if (v!=-1) return v;
if (k>2*n) return v=0;
if (i==0) return v=1;
if (i==j) return v=2;
if (k%2==0){
bool draw=false;
for (int ne:g[i]){
int ans=dfs(k+1,ne,j);
if (ans==1) return v=1;
if (ans==0) draw=true;
}
if (draw) return v=0;
return v=2;
}else{
bool draw=false;
for (int ne:g[j]){
if (ne==0) continue;
int ans=dfs(k+1,i,ne);
if (ans==2) return v=2;
if (ans==0) draw=true;
}
if (draw) return v=0;
return v=1;
}
}
int catMouseGame(vector<vector<int>>& graph) {
g=graph;
n=g.size();
f=vector<vector<vector<int>>>(2*n+2,vector<vector<int>>(n,vector<int>(n,-1)));
return dfs(0,1,2);
}
};
[Go Back~](# LeetCode题解)
section16-7: 状态机dp+状压dp
1、最佳买卖股票时机含冷冻期
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
vector<vector<int>> f(n,vector<int>(2,0));
f[0][0] = 0, f[0][1] = -prices[0];
for(int i=1;i<n;i++){
f[i][0] = max(f[i-1][0], f[i-1][1]+prices[i]);
if(i>=2) f[i][1] = max(f[i-1][1], f[i-2][0]-prices[i]);
else f[i][1] = max(f[i-1][1], -prices[i]);
}
return f[n-1][0];
}
};
// 状态压缩
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
int a0 = 0, a1 = -prices[0];
int last_a0=a0, last_a1 = a1, last_a2=0;
for(int i=1;i<n;i++){
a0 = max(last_a0, last_a1+prices[i]);
if(i>=2) a1 = max(last_a1, last_a2-prices[i]);
else a1 = max(last_a1, -prices[i]);
last_a2 = last_a0; last_a1 = a1; last_a0 = a0;
}
return a0;
}
};
2、学生出勤记录 II
const int mod=1e9+7;
class Solution {
public:
int checkRecord(int n) {
vector<vector<vector<int>>>f(n+1,vector<vector<int>>(2,vector<int>(3,0)));
f[0][0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<2;j++){
for(int k=0;k<3;k++){
if(!j) f[i+1][j+1][0] = (f[i+1][j+1][0]+f[i][j][k]) % mod;
if(k+1<=2) f[i+1][j][k+1] = (f[i+1][j][k+1] + f[i][j][k]) % mod;
f[i+1][j][0] = (f[i+1][j][0] + f[i][j][k]) % mod;
}
}
}
int res=0;
for(int j=0;j<2;j++)
for(int k=0;k<=2;k++)
res = (res+f[n][j][k])%mod;
return res;
}
};
3、买卖股票的最佳时机含手续费
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int n=prices.size();
vector<int> f(n,0), g(n,0);
f[0]=0, g[0]=-prices[0];
for(int i=1;i<n;i++){
f[i] = max(f[i-1], g[i-1]+prices[i]-fee);
g[i] = max(g[i-1], f[i-1]-prices[i]);
}
return f[n-1];
}
};
// 状态压缩
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int n=prices.size();
int a0=0, b0=-prices[0];
for(int i=1;i<n;i++){
int last_a0 = a0, last_b0 = b0;
a0 = max(last_a0, last_b0+prices[i]-fee);
b0 = max(last_b0, last_a0-prices[i]);
}
return a0;
}
};
4、我能赢吗 【×】
class Solution {
public:
vector<int> f;
int n;
bool canIWin(int m, int total) {
n=m;
if((n+1)*n < 2*total) return false;
if(!total) return true;
f.resize(1<<(n+1),-1);
return dfs(0,total);
}
bool dfs(int u, int t){ // 是否使用的状态通过整数u表示
if(f[u]!=-1) return f[u];
if(t<=0) return f[u]=false;
for(int i=1;i<=n;i++){
if(!(u & 1<<i)){
if(!dfs(u+(1<<i), t-i))
return f[u]=true;
}
}
return f[u]=false;
}
};
[Go Back~](# LeetCode题解)
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。