1:斐波那契系列问题的递归和动态规划解决。
1)给定整数N,返回斐波那契数列第N项
//递归实现 ;T(n)=O(2^n)
int f1(int N){
if(N==0)return 0;
if(N==1||N==2)return 1;
return f1(N - 1) + f1(N - 2);
}
//动态规划实现 T(n)=O(n) S(n)=O(n)
int f2(int N){
int dp[N+1];//静态数组
dp[0]=0;
dp[1]=1;
for(int i=2;i<=N;i++)
dp[i]=dp[i-1]+dp[i-2];
return dp[N];
}
//动态规划实现,不额外开辟空间 T(n)=O(n)
int f3(int N){
if(N<1)return 0;
if(N==1||N==2)return 1;
int pre=1,cur=1,res;
for(int i=3;i<=N;i++){
res=pre+cur;
pre=cur;
cur=res;
}
return res;
}
Fibonacci数列 时间复杂度为 O(logN)解法
class Solution {
public:
//求解矩阵m的p次方
vector<vector<int>> matrixPower(vector<vector<int>> m, int p) {
//m是个方阵
int len = m.size();
//初始化全为0
vector<vector<int>> res(len, vector<int>(len, 0));
for (int i = 0; i < len; i++)
res[i][i] = 1;//对角阵,相当于整数1
vector<vector<int>>temp=m;
for(;p!=0;p>>=1){
if((p&1)!=0)
res=mulMatrix(res,temp);
temp=mulMatrix(temp,temp);//比特串为0则temp翻倍,为1则为奇数串,与res相乘
}
return res;
}
//计算两矩阵相乘
vector<vector<int>> mulMatrix(vector<vector<int>> m1, vector<vector<int>> m2) {
int m = m1.size();
int p = m2[0].size();
int n = m1[0].size();
vector<vector<int>> res(m, vector<int>(p, 0));
//两矩阵相乘 m*n n*p
//要注意谁在外层
for (int j = 0; j < m; j++) {
for (int k = 0; k < p; k++) {
for (int i = 0; i < n; i++) {
res[j][k] += m1[j][i] * m2[i][k];
}
}
}
return res;
}
//求解斐波那契数列,调用之前的辅助函数
int Fibonacci(int N){
if(N<1)return 0;
if(N==1||N==2)return 1;
//状态转移矩阵为{[1,1],[1,0]}
vector<vector<int>>base(2, vector<int>(2, 1));
base[1][1]=0;
vector<vector<int>>res=matrixPower(base,N-2);
return res[0][0]+res[1][0];
}
};
2)台阶问题
递推关系式为S(n)=S(n-1)+S(n-2),与Fibonacci问题求解方法一样
3)估计成熟的牛的数目问题
递推关系为C(n)=C(n-1)+C(n-3),是一个三阶递推序列。利用矩阵求解方法如下。
状态转移方程为{[1,1,0],[0,,0,1],[1,0,0]}
int cowNum(int N){
if(N<1)return 0;
if(N==1||N==2||N==3)return N;
int a[3][3]={{1,1,0},{0,0,1},{1,0,0}};
vector<vector<int>>base(3,vector<int>(3,-1));
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
base[i][j]=a[i][j];//利用二维数组给vector赋初值
vector<vector<int>>res=matrixPower(base,N-3);
return 3*res[0][0]+2*res[1][0]+res[2][0];
}
2:矩阵的最小路径和
class Solution{
public:
//经典动态规划问题 T(n)=O(m*n)
int minPathSum1(vector<vector<int>>m){
if(m.size()==0||m[0].size()==0)
return -1;
int row=m.size();
int col=m[0].size();
int dp[row][col];
dp[0][0]=m[0][0];
//最左侧一列和最上面一行的最短路径分别为竖直方向和水平方向
//提前处理
for(int i=1;i<row;i++)
dp[i][0]=dp[i-1][0]+m[i][0];
for(int i=1;i<col;i++)
dp[0][i]=dp[0][i-1]+m[0][i];
for(int i=1;i<row;i++){
for(int j=1;j<col;j++){//每一步最优->全局最优
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+m[i][j];
}
}
return dp[row-1][col-1];
}
//进阶版动态规划求解,S(n)=O(col)
//利用滚动数组的方法
int minPathSum2(vector<vector<int>>m){
if(m.size()==0||m[0].size()==0)
return -1;
int row=m.size();
int col=m[0].size();
int arr[col];
arr[0]=m[0][0];
//先处理第一行
for(int i=1;i<col;i++)
arr[i]=arr[i-1]+m[0][i];
for(int i=1;i<row;i++){
//处理逐行遍历的首个元素,即更新arr[0]
arr[0]=arr[0]+m[i][0];
for(int j=1;j<col;j++){
arr[j]=min(arr[j-1],arr[j])+m[i][j];
}
}
return arr[col-1];
}
};
3:换钱的最少货币数
class Solution{
public:
//类似求解矩阵的最小路径和 S(n)=T(n)=O(N*aim)
int minCoins1(vector<int>arr,int aim){
if(arr.empty()||aim==0)
return -1;
int len=arr.size();
int max=INT_MAX;
vector<vector<int>>dp(len,vector<int>(aim+1,max));
for(int i=0;i<len;i++)
dp[i][0]=0;
for(int j=1; j <= aim; j++){
dp[0][j]=max;//处理第一行,dp[0][j-arr[0]]!=max意思为满减?
if(j-arr[0]>=0&&dp[0][j-arr[0]]!=max)
dp[0][j]=dp[0][j-arr[0]]+1;
}
int left=0;
for(int i=1;i<len;i++){
for(int j=1;j<=aim;j++){
left=max; //二维数组遍历
if(j-arr[i]>=0&&dp[i][j-arr[i]]!=max)
left=dp[i][j-arr[i]]+1;
dp[i][j]=min(left,dp[i-1][j]);
}
}
return dp[len-1][aim]!=max?dp[len-1][aim]:-1;
}
//利用滚动数组实现优化
//T(n)=O(n*aim) S(n)=O(aim)
int minCoins(vector<int>arr,int aim){
if(arr.empty()||aim==0)
return -1;
int len=arr.size();
int max=INT_MAX;
int dp[aim+1];
dp[0]=0;
for(int j=1;j<=aim;j++){
dp[j]=max;
if(j-arr[0]>=0&&dp[j-arr[0]]!=max)
dp[j]=dp[j-arr[0]]+1;
}
int left=0;
for(int i=1;i<len;i++){
for(int j=1;j<=aim;j++){
left=max;
if(j-arr[i]>=0&&dp[j-arr[i]]!=max)
left=dp[j-arr[i]]+1;
dp[j]=min(left,dp[j]);
}
}
return dp[aim]!=max?dp[aim]:-1;
}
};
4:换钱的方法数
class Solution{
public:
//暴力递归
int coins1(vector<int>arr,int aim){
if(aim<1||arr.empty())
return 0;
return process1(arr, 0, aim);
}
int process1(vector<int>arr, int index, int aim){
int res=0;
if(index==arr.size())
res=(aim==0)?1:0;
for(int i=0;arr[index]*i<=aim;i++)
res+= process1(arr, index + 1, aim - arr[index] * i);
return res;
}
//带有记忆化搜索的递归方式
int coins2(vector<int>arr,int aim){
if(arr.empty()||aim<0)
return -1;
vector<vector<int>>map(arr.size()+1,vector<int>(aim+1,0));
return process2(arr,0,aim,map);
}
int process2(vector<int>arr,int index,int aim,vector<vector<int>>map){
int res=0;
if(index==arr.size()){
res=aim==0?1:0;
}
else{
int mapValue=0;
for(int i=0;arr[index]*i<=aim;i++){
mapValue=map[index+1][aim-arr[index]*i];
if(mapValue!=0){
res+=mapValue==-1?0:mapValue;
} else{
res+=process2(arr,index+1,aim-arr[index]*i,map);
}
}
}
map[index][aim]=res==0?-1:res;
return res;
}
};