动态规划-2 发现重叠子问题

343.整数拆分

在这里插入图片描述

class Solution {
public:
    int integerBreak(int n) {
            if(n<=3) return n-1;
            int a=n/3;
            if(n%3==1)  return 4*pow(3,a-1);
            else if(n%3==2)  return 2*pow(3,a);
            else return pow(3,a);
    }
};

这是数学推导的解法,看了别人的题解自己做笔记打的,(为什么别人这么强),可能懒还是一个大原因,拿出纸笔写写画画有时候就会发现没有那么难 附上我的笔记(字怎么这么丑

在这里插入图片描述
递推表达式F(n)=max{i∗(n−i),i∗F(n−i)}, (i=1,2,…,n−1)

class Solution {
     int mem[60];//存Fn
public:
    int integerBreak(int n) {
           int res=-1;
           if(n==2) return 1;
           if(mem[n]!=0) return mem[n];
           for(int i=1;i<n;i++)
           {
                res=max(res,max(i*(n-i),i*integerBreak(n-i)));
           }
           mem[n]=res;//每次算完都要把结果存起来
           return res;  
    }
    
};

记忆化搜索,用数组记录每次计算完的值,避免大量的重复运算,与爬楼梯那题一样的想法

class Solution {
public:
    int integerBreak(int n) {
          int dp[60]={};  
          dp[2]=1;
          for(int i=3;i<=n;i++)
          {
              for(int j=1;j<i;j++)
              {
                  dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]));
              }
          }
          return dp[n];
    }
    
};

动态规划,将递归转换为自底向上的方式计算,注意数组要初始化为0

279完全平方数

在这里插入图片描述

class Solution {
    int mem[20000]={};
public:
    int numSquares(int n) {
        if(mem[n]>0) return mem[n];
        for(int i=1;i<=(int)sqrt(n);i++)
        {
            mem[i*i]=1;//完全平方数就是1
        }
        if(mem[n]>0) return mem[n];
        if(n==1) return 1;
        for(int i=2;i<=n;i++)
        {
            int res=INT_MAX;
            if(mem[i]>0) continue;
            for(int j=(int)sqrt(i);j>=1;j--)
            {
                res=min(res,numSquares(i-j*j)+1);
            }
            mem[i]=res;
        }
        return mem[n];
    }
};

带有记忆化的递归,忘记记录写了多久emmm,写了可能不到十分钟,但是改bug改了可能有半个小时,代码能力还是太差了

91.解码方法

在这里插入图片描述

这题看了很久还是不太会怎么解,知道方向但是没有特别耐心的找规律,这题重点就是把情况列出来讨论 以下是题解的分析,很清楚,把情况列完之后就很容易求解。
还有一个重要的点是,dp[i]只和当前的前两个有关系,所以可以不用一维数组来存,直接变量代替就可以了,节省空间。

在这里插入图片描述

class Solution {
public:
    int numDecodings(string s) {
        if(s[0]=='0') return 0;
        int cur=1,pre=1,prepre=1;
        for(int i=1;i<s.size();i++)
        {
            if(s[i]=='0')
            {
                if(s[i-1]=='1'||s[i-1]=='2') cur=prepre;
                else return 0;
            }
            else if(s[i-1]=='1') cur=pre+prepre;
            else if(s[i-1]=='2'&&s[i]>='1'&&s[i]<='6') cur=pre+prepre;
            prepre=pre;
            pre=cur;
        
        }
        return cur;
    }
};

62 不同路径

在这里插入图片描述

emmm真的没有想到这么快就完成了,大概就十分钟,写完就直接过了还是双百,发现dp解答的都很容易双百
主要还是发现规律找出递推表达式,我在纸上列了3*3的找到了规律,再处理一下边界就解决了
dp[i][j]表示从起点到i列j行共有多少条,emm秀一下双百
在这里插入图片描述
但是冷静一下这个算法的时间复杂度和空间复杂度都是O(M *N),题解区还是有更优化的方案的,我对这个双百的含金量表示怀疑

class Solution {
public:
    int uniquePaths(int m, int n) {
        int dp[102][102];
        for(int i=1;i<=m;i++)
        {
            dp[i][1]=1;
        }
        for(int i=1;i<=n;i++)
        {
            dp[1][i]=1;
        }
        for(int i=2;i<=m;i++)
        {
            for(int j=2;j<=n;j++)
              dp[i][j]=dp[i-1][j]+dp[i][j-1];
        }
        return dp[m][n];
        
    }
};

63不同路径2

在这里插入图片描述

和上题的递归方程是一样的,只要把有障碍物的地方设为0就可,还有一个容易出错的点就是在边界上,01如果是障碍物,那么第一行从02开始之后所有都是0

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int m=obstacleGrid.size();
        int n=obstacleGrid[0].size();
        int dp[102][102];
        memset(dp,-1,sizeof(dp));
        for(int i=0;i<m;i++)//第一列的边界处理
        {
            if(obstacleGrid[i][0]==1)
            {
                int index=i;
                for(int j=index;j<m;j++)
                  dp[j][0]=0;
                break;
            }
            else dp[i][0]=1;
        }  
        for(int j=0;j<n;j++) //第一行的边界处理
        {
            if(obstacleGrid[0][j]==1)
            {
                int index=j;
                for(int i=index;i<n;i++)
                  dp[0][i]=0;
                break;
            }
            else dp[0][j]=1;
        }  
        for(int i=1;i<m;i++) //中间遇到障碍物把相应的位置设为0
        {
            for(int j=1;j<n;j++)
            {
                if(obstacleGrid[i][j]==1)
                   dp[i][j]=0;
            }
        }
        for(int i=1;i<m;i++)//核心递推
        {
            for(int j=1;j<n;j++)
            {
                if(dp[i][j]==-1) //不是障碍物
                 dp[i][j]=dp[i-1][j]+dp[i][j-1];
            }
              
        }
       // return obstacleGrid[1][1];
        return dp[m-1][n-1];

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值