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];
}
};