【专题】动态规划
刷题顺序来自https://leetcode-cn.com/circle/article/48kq9d/
文章目录
- 【专题】动态规划
- 更新记录
- 数组中的动态规划
- [509. 斐波那契数](https://leetcode-cn.com/problems/fibonacci-number/)
- [70. 爬楼梯](https://leetcode-cn.com/problems/climbing-stairs/)
- [338. 比特位计数](https://leetcode-cn.com/problems/counting-bits/)
- [45. 跳跃游戏 II(***超时,等到学完贪心重新做)](https://leetcode-cn.com/problems/jump-game-ii/)
- [55. 跳跃游戏](https://leetcode-cn.com/problems/jump-game/)
- [198. 打家劫舍](https://leetcode-cn.com/problems/house-robber/)
- [213. 打家劫舍 II](https://leetcode-cn.com/problems/house-robber-ii/)
- [650. 只有两个键的键盘](https://leetcode-cn.com/problems/2-keys-keyboard/)
- [91. 解码方法](https://leetcode-cn.com/problems/decode-ways/)
更新记录
1.29
509、70、338、45
1.30
55、198、213、650、91
数组中的动态规划
509. 斐波那契数
/*
* dp[i]=dp[i-1]+dp[i-2];
* dp[0]=0;
* dp[1]=1;
*/
class Solution {
public:
int fib(int n) {
int even=0,odd=1;
for(int i=2;i<=n;i++){
if(i%2==0){
even=even+odd;
}
else{
odd=even+odd;
}
}
return n%2==0 ? even:odd;
}
};
70. 爬楼梯
/*
*dp[i]记录爬到第i节楼梯的方法的数目
*最后一次爬楼梯,只有两种情况:
*要么在倒数第1个台阶,要么在倒数第2个台阶。所以:
*dp[i]=dp[i-1]+dp[i-2]
*dp[2]=2;
*dp[1]=1;
*/
class Solution {
public:
int climbStairs(int n) {
int odd=1,even=2;
for(int i=3;i<=n;i++){
if(i%2==0){
even=even+odd;
}
else{
odd=even+odd;
}
}
return n%2==0 ? even:odd;
}
};
338. 比特位计数
/*
*even=(even/2)<<1
*odd=(odd/2)<<1+1
*所以偶数和它的二分之一的二进制中的1个数相等,如8和4和2都只有1个1
*奇数就不解释了
*/
class Solution {
public:
vector<int> countBits(int num) {
vector<int> count_bits;
count_bits.push_back(0);
for(int i=1;i<=num;i++){
i%2==0 ? count_bits.push_back(count_bits[i/2]): count_bits.push_back(count_bits[i/2]+1);
}
return count_bits;
}
};
45. 跳跃游戏 II(***超时,等到学完贪心重新做)
//思路:left 和 right 之间 是同一个最小step能到达的范围,
//step+1则为范围right+1,max{dp[i]+i},left<=i<=right
class Solution {
public:
int jump(vector<int>& nums) {
if(nums.size()==1)
return 0;
int left=1;
int right=nums[0];
int step=1;
int max=nums[0];
while(right<nums.size()-1){
step++;
for(int i=left;i<=right;i++){
if(max<i+nums[i]){
max=i+nums[i];
}
}
right=max;
}
return step;
}
};
55. 跳跃游戏
class Solution {
public:
bool canJump(vector<int>& nums) {
if(nums.size()==1)
return true;
int left=1;
int right=nums[0];
int max=nums[0];
while(right<nums.size()-1){
for(int i=left;i<=right;i++){
if(max<i+nums[i]){
max=i+nums[i];
}
}
if(max==right)
return false;
right=max;
}
return true;
}
};
性能很差
198. 打家劫舍
//用两个数组,A[i]表示偷当前家的总金额,B[i]表示不偷
//那么A[i]=B[i-1]+nums[i],B[i]=max{A[i-1],B[i-1]}
class Solution {
public:
int rob(vector<int>& nums) {
int length=nums.size();
if(length==0)
return 0;
int *A=new int[length];
int *B=new int[length];
A[0]=nums[0];
B[0]=0;
for(int i=1;i<length;i++){
A[i]=B[i-1]+nums[i];
B[i]=(A[i-1]>B[i-1]?A[i-1]:B[i-1]);
}
return A[length-1]>B[length-1]?A[length-1]:B[length-1];
}
};
213. 打家劫舍 II
//两种情况:不偷0家:正常和上面一样计算1到n-1的方程的值;偷0家,那么1不偷,n-1不能偷,计算2到n-2的方程
class Solution {
public:
int rob(vector<int>& nums) {
int length=nums.size();
if(length==0)
return 0;
if(length==1)
return nums[0];
if(length==2)
return nums[0]>nums[1]? nums[0]:nums[1];
if(length==3)
return nums[0]>nums[1]?(nums[0]>nums[2]?nums[0]:nums[2]):(nums[1]>nums[2]?nums[1]:nums[2]);
int *A=new int[length];
int *B=new int[length];
//不偷0
A[1]=nums[1];
B[1]=0;
for(int i=2;i<length;i++){
A[i]=B[i-1]+nums[i];
B[i]=(A[i-1]>B[i-1]?A[i-1]:B[i-1]);
}
int max1=A[length-1]>B[length-1]?A[length-1]:B[length-1];
//偷0
A[2]=nums[2];
B[2]=0;
for(int i=3;i<length-1;i++){
A[i]=B[i-1]+nums[i];
B[i]=(A[i-1]>B[i-1]?A[i-1]:B[i-1]);
}
int max2=A[length-2]>B[length-2]?(A[length-2]+nums[0]):(B[length-2]+nums[0]);
return max1>max2?max1:max2;
}
};
650. 只有两个键的键盘
//dp[1]=0
//dp[i]=min{dp[j]+1(复制的一次)+(i/j-1)(粘贴的次数)|j为i的所有约数}
//
class Solution {
public:
int minSteps(int n) {
int *dp=new int[n+1];
dp[1]=0;
for(int i=2;i<=n;i++){
dp[i]=i;
}
for(int i=2;i<=n/2;i++){
int mul=2;
int j=i*mul;
while(j<=n){
int temp=dp[i]+mul;
if(temp<dp[j]){
dp[j]=temp;
}
mul++;
j+=i;
}
}
return dp[n];
}
};
91. 解码方法
class Solution {
public:
int numDecodings(string s) {
if(s[0]=='0')
return 0;
int size=s.size();
int *dp=new int[size];
dp[0]=1;
if(size==1){
return 1;
}
//判断是否合法
for(int i=1;i<size;i++){
if(s[i]=='0'){
if(s[i-1]!='1'&&s[i-1]!='2')
return 0;
}
}
dp[1]=(s[1]=='0')?1:(canCombined(s,1) ? 2:1);
if(size==2){
return dp[1];
}
if(s[1]=='0'||s[2]=='0'){
dp[2]=1;
}
else{
dp[2]=canCombined(s,2)?(canCombined(s,1)?3:2):(canCombined(s,1)?2:1);
}
if(size==3){
return dp[2];
}
for(int i=3;i<size;i++){
switch (whichCase(s,i)){
case 0:
dp[i]=dp[i-2];
break;
case 1:
dp[i]=dp[i-3]+2*dp[i-2];
break;
case 2:
dp[i]=2*dp[i-2];
break;
case 3:
dp[i]=dp[i-1];
break;
}
}
return dp[size-1];
}
bool canCombined(string s,int i){
//i>=1
if(s[i-1]=='0'||s[i-1]>'2')
return false;
if(s[i-1]=='2'&&s[i]>'6')
return false;
return true;
}
int whichCase(string s,int i){
if(s[i]=='0') return 0;
return canCombined(s,i)?(canCombined(s,i-1)?1:2):3;
}
};