动态规划基础
70. 爬楼梯
题目描述
题解1 使用数组
class Solution {
public:
int climbStairs(int n) {
if(n<2)return n;
vector<int>step(n+1);
step[0]=1;
step[1]=1;
for(int i=2;i<n+1;i++)
{
step[i]=step[i-1]+step[i-2];
}
return step[n];
}
};
题解2 两个临时变量
int climbStairs(int n) {
if(n<2)return n;;
int tmp;
int last1=1;
int last2=1;
for(int i=2;i<n+1;i++)
{
tmp=last1+last2;
last2=last1;
last1=tmp;
}
}
120. 三角形最短路径和
题目描述
题解1 两行变量记录 复杂度O(n)
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n=triangle.size();
vector<int> lastbest(n,INT_MAX);
vector<int> tmpbest(n,INT_MAX);
lastbest[0]=triangle[0][0];
tmpbest[0]=triangle[0][0];
for(int i=1;i<n;i++)
{
for(int j=0;j<i+1;j++)
{
if(j==0)tmpbest[j]=lastbest[j]+triangle[i][j];
else if(j<i)tmpbest[j]=min(lastbest[j]+triangle[i][j],lastbest[j-1]+triangle[i][j]);
else
tmpbest[j]=lastbest[j-1]+triangle[i][j];
//cout<<tmpbest[j]<<endl;
}
lastbest=tmpbest;
}
int ret=INT_MAX;
for(int i=0;i<n;i++)
{
ret=min(ret,tmpbest[i]);
}
return ret;
}
};
题解2 一行变量 自顶向下 空间复杂度O(n)
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n=triangle.size();
vector<int> lastbest(n,INT_MAX);
vector<int> tmpbest(n,INT_MAX);
//lastbest[0]=triangle[0][0];
tmpbest[0]=triangle[0][0];
for(int i=1;i<n;i++)
{
for(int j=i;j>=0;j--)
{
if(j==0)tmpbest[j]=tmpbest[j]+triangle[i][j];
else if(j<i)tmpbest[j]=min(tmpbest[j]+triangle[i][j],tmpbest[j-1]+triangle[i][j]);
else
tmpbest[j]=tmpbest[j-1]+triangle[i][j];
//cout<<tmpbest[j]<<endl;
}
//lastbest=tmpbest;
}
int ret=INT_MAX;
for(int i=0;i<n;i++)
{
ret=min(ret,tmpbest[i]);
}
return ret;
}
};
题解3 自底向上 不需要额外空间
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n=triangle.size();
for(int i=n-2;i>=0;i--)
{
for(int j=0;j<triangle[i].size();j++)
{
triangle[i][j]=triangle[i][j]+min(triangle[i+1][j],triangle[i+1][j+1]);
}
}
return triangle[0][0];
}
};
343. 整数拆分
题目描述
题解1 动态规划
class Solution {
public:
int max3(int x,int y,int z)
{
return x>y?x>z?x:z:y>z?y:z;
}
int integerBreak(int n) {
vector<int> ret(n+1,0);
ret[1]=1;
for(int i=2;i<n+1;i++)
{
//cout<<"sdfdfs0"<<endl;
for(int j=1;j<i;j++)
{
//cout<<(i-j)*ret[i-j]<<endl;
ret[i]=max3((j)*ret[i-j],ret[i],(i-j)*(j));//(i-j)*(j)为i-j不拆分的情况
}
}
return ret[n];
}
};
279. 完全平方数
题目描述
题解1 使用队列进行图的遍历(时间较短)
题解2 动态规划
class Solution {
public:
int numSquares(int n) {
vector<int> ret(n+1,INT_MAX);
ret[1]=1;
ret[0]=0;
for(int i=2;i<n+1;i++){
for(int j=1;i-j*j>=0;j++)
{
ret[i]=min(ret[i],1+ret[i-j*j]);
}
}
return ret[n];
}
};
91. 解码方法
题目描述
题解1 难点在于分类讨论
class Solution {
public:
int numDecodings(string s) {
int n=s.size();
vector<int> ret(n+1);
if(s[0]=='0'){return 0;}
else
{ret[0]=1;
ret[1]=1;}
for(int i=2;i<n+1;i++)
{
//if(s[i-1]=='0'&&s[i-2]=='0')return 0;
if(s[i-1]=='0')
{
if(s[i-2]!='1'&&s[i-2]!='2') return 0;
ret[i]=ret[i-2];
}
else if((s[i-2]=='2'&&s[i-1]>'6')||s[i-2]>'2'||s[i-2]=='0')
{
ret[i]=ret[i-1];
}
else
{ret[i]=ret[i-2]+ret[i-1];}
}
return ret[n];
}
};
62. 不同路径
题目描述
题解1
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> dp=vector<vector<int>>(m,vector<int>(n,0));
for(int i=0;i<m;i++)
{
dp[i][0]=1;
}
for(int i=0;i<n;i++)
{
dp[0][i]=1;
}
for(int i=1;i<m;i++)
{
for(int j=1;j<n;j++)
{
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
}
};
63. 不同路径 II
题目描述
题解1 额外空间
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m=obstacleGrid.size();
int n=obstacleGrid[0].size();
vector<vector<int>> dp=vector<vector<int>>(m,vector<int>(n,0));
for(int i=0;i<m;i++)
{
if(obstacleGrid[i][0]==1){dp[i][0]=0;break;}
dp[i][0]=1;
}
for(int i=0;i<n;i++)
{
if(obstacleGrid[0][i]==1){dp[0][i]=0;break;}
dp[0][i]=1;
}
for(int i=1;i<m;i++)
{
for(int j=1;j<n;j++)
{
if(obstacleGrid[i][j]==1){dp[i][j]=0;continue;}
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
}
};
题解2 不使用额外空间
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m=obstacleGrid.size();
int n=obstacleGrid[0].size();
bool test=false;
if(obstacleGrid[0][0]==1)test=true;
int flag=false;
for(int i=0;i<m;i++)
{
if(flag||obstacleGrid[i][0]==1){obstacleGrid[i][0]=0;flag=true;}
else
obstacleGrid[i][0]=1;
}
flag=test;
for(int i=1;i<n;i++)
{
if(flag||obstacleGrid[0][i]==1){obstacleGrid[0][i]=0;flag=true;}
else
obstacleGrid[0][i]=1;
}
for(int i=1;i<m;i++)
{
for(int j=1;j<n;j++)
{
if(obstacleGrid[i][j]==1){obstacleGrid[i][j]=0;continue;}
obstacleGrid[i][j]=obstacleGrid[i-1][j]+obstacleGrid[i][j-1];
}
}
return obstacleGrid[m-1][n-1];
}
};
状态定义和状态转移
198. 打家劫舍
题目描述
题解
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==0)return 0;
vector<int> ret(n);
ret[0]=nums[0];
if(n==1)return nums[0];
ret[1]=max(nums[0],nums[1]);
for(int i=2;i<n;i++)
{
ret[i]=max(ret[i-2]+nums[i],ret[i-1]);
}
return ret[n-1];
}
};
213. 打家劫舍 II
题目描述
题解1 使用两个变量 分别为偷了第一间和没偷第一间的最大值
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==0)return 0;
vector<int> ret(n);
vector<int> nret(n);
nret[0]=0;
ret[0]=nums[0];
if(n==1)return nums[0];
ret[1]=max(nums[0],nums[1]);
nret[1]=max(nums[1],0);
for(int i=2;i<n;i++)
{
ret[i]=max(ret[i-2]+nums[i],ret[i-1]);
nret[i]=max(nret[i-2]+nums[i],nret[i-1]);
if(i==n-1)
ret[n-1]=max(ret[n-2],nret[n-3]+nums[n-1]);
}
// nret[n-1]=max()
return ret[n-1];
}
};
337. 打家劫舍 III
题目描述
题解1 两个变量 偷和不偷 可以使用pair类型
class Solution {
pair<int,int> dfs(TreeNode* root)
{
//pair<int,int> ret=make_pair(0,0);
if(root==NULL)return make_pair(0,0);
pair<int,int> lmax=dfs(root->left);
pair<int,int> rmax=dfs(root->right);
return make_pair(lmax.second+rmax.second+root->val,max(lmax.first,lmax.second)+max(rmax.first,rmax.second));
}
public:
int rob(TreeNode* root) {
//root->left
pair<int,int> res=dfs(root);
return max(res.first,res.second);
}
};
面试中的背包问题
416. 分割等和子集
题目描述
题解1 记忆化搜索 bool类型
class Solution {
bool helper(vector<int>&nums ,int c,int index,vector<vector<int>>&memo)
{
//cout<<c<<" "<<index<<endl;
if(index<0||c<0)return false;
if(c==0)return true;
if(memo[index][c]!=-1)return memo[index][c]==1;
memo[index][c]=(helper(nums,c,index-1,memo)||helper(nums,c-nums[index],index-1,memo))==1?1:0;
return memo[index][c]==1;
}
public:
bool canPartition(vector<int>& nums) {
int n=nums.size();
int sum=0;
for(int i=0;i<n;i++)
{
sum+=nums[i];
}
if(sum%2!=0)return false;
//cout<<sum<<endl;
vector<vector<int>>memo(n,vector<int>(sum/2+1,-1) );
return helper(nums,sum/2,n-1,memo);
}
};
题解2 动态规划
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n=nums.size();
int sum=0;
for(int i=0;i<n;i++)
{
sum+=nums[i];
}
if(sum%2!=0)return false;
vector<bool> ret(sum/2+1,false);
sum=sum/2;
//cout<<sum+1<<endl;
for(int i=0;i<sum+1;i++)
{
ret[i]=(nums[0]==i);
//cout<<i<<endl;
}
for(int i=1;i<n;i++)
{
for(int j=sum;j>=nums[i];j--)
{
//cout<<i<<' '<<j<<endl;
ret[j]=(ret[j]||ret[j-nums[i]]);
}
}
return ret[sum];
}
};
322. 零钱兑换
题目描述
题解1 排序后提前结束
class Solution {//排序过了 提前跳过
public:
int coinChange(vector<int>& coins, int amount) {
int MAX=amount+1;
vector<int> ret(amount+1,MAX);
sort(coins.begin(),coins.end());
ret[0]=0;
for(int i=coins[0];i<amount+1;i++)
{
for(int j=0;j<coins.size()&&coins[j]<=i;j++)
{
ret[i]=min(1+ret[i-coins[j]],ret[i]);
}
}
return ret[amount]==MAX?-1:ret[amount];
}
};
题解2 没有排序
class Solution {//没有排序
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> ret(amount+1,INT_MAX);
sort(coins.begin(),coins.end());
ret[0]=0;
for(int i=coins[0];i<amount+1;i++)
{
for(int j=0;j<coins.size()&&coins[j]<=i;j++)
{
//cout<<i<<" "<<coins[j]<<endl;
if(ret[i-coins[j]]==INT_MAX)
{//cout<<'s'<<endl;
continue;}
//cout<<i<<"2"<<coins[j]<<endl;
ret[i]=min(1+ret[i-coins[j]],ret[i]);
}
}
return ret[amount]==INT_MAX?-1:ret[amount];
}
};
377. 组合总和 Ⅳ
题目描述
题解1
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
int n=nums.size();
vector<unsigned long long>ret(target+1,0);
ret[0]=1;
for(int i=1;i<target+1;i++)
{
for(int j=0;j<nums.size();j++)
{
if(nums[j]<=i)
{
ret[i]=ret[i]+ret[i-nums[j]];
}
}
}
return ret[target];
}
};
474. 一和零
题目描述
题解 二维背包问题
139
494
LIS问题
300. 最长上升子序列
题目描述
题解1 动态规划 以n结尾的最长上升子序列
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
if(n==0)return 0;
vector<int> res(n,1);
int ret=1;
for(int i=1;i<n;i++)
{
for(int j=0;j<i;j++)
{
if(nums[i]>nums[j])
{
//cout<<'a'<<endl;
res[i]=max(res[i],res[j]+1);
}
}
}
for(int i=0;i<n;i++)
{
ret=max(ret,res[i]);
}
return ret;
}
};
题解2 贪心算法+二分查找 难点在找upper bound
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int len = 1, n = (int)nums.size();
if (n == 0) return 0;
vector<int> d(n + 1, 0);
d[len] = nums[0];
for (int i = 1; i < n; ++i) {
if (nums[i] > d[len]) d[++len] = nums[i];
else{
int l = 1, r = len, pos = 0; // 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 pos 设为 0
while (l <= r) {
int mid = (l + r) >> 1;
if (d[mid] < nums[i]) {
pos = mid;
l = mid + 1;
}
else r = mid - 1;
}
d[pos + 1] = nums[i];
}
}
return len;
}
};
376. 摆动序列
题目描述
题解1 类似LIS
两个序列 值为以该元素为结尾的 一个是比上一个元素大 (上一个元素比上上个元素小的序列) 另一个是比上一个元素小(上一个元素比上上个元素大)的序列
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int n=nums.size();
if(n==0)return 0;
vector<int> maxres(n,1);
vector<int> minres(n,1);
for(int i=1;i<n;i++)
{
for(int j=0;j<i;j++)
{//相等直接跳过
if(nums[i]>nums[j])
{
maxres[i]=max(maxres[i],minres[j]+1);
}
else if(nums[i]<nums[j])
{
minres[i]=max(minres[i],maxres[j]+1);
}
}
}
int ret=0;
for(int i=0;i<n;i++)
{
ret=max(ret,maxres[i]);
ret=max(ret,minres[i]);
}
return ret;
}
};