日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

玩转算法之面试第九章-动态规划

發(fā)布時(shí)間:2024/7/5 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 玩转算法之面试第九章-动态规划 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

動態(tài)規(guī)劃:
9-12
斐波那契數(shù)列

對重復(fù)計(jì)算,進(jìn)行優(yōu)化,進(jìn)行記憶化搜索



假設(shè)基本的問題已經(jīng)被解決,依次內(nèi)推。

動態(tài)規(guī)劃:將原問題拆解成若干個(gè)子問題,同時(shí)保存子問題的答案,使得每個(gè)子問題只求解一次,最終獲得原問題的答案。

leetcode 20

自頂向下分析可得:
f(n)=f(n-1)+f(n-2)

將上述函數(shù)修改動態(tài)規(guī)劃寫法:

部分代碼如下:

在這里插入代碼片 //跳臺階 #include<iostream> #include<vector> using namespace std;class Solution{private:vector<int> memo;int calcWays(int n){if(n==0 || n==1)return 1;//if(n==1)//return 1;//if(n==2)//return 2;if(memo[n]==-1)memo[n]=calcWays(n-1)+calcWays(n-2);retrun memo[n]; }public:int climbStairs(int n){memo=vector<int>(n+1,-1);return calcWays(n);} };int main(){return 0; }//調(diào)臺階修改成動態(tài)規(guī)劃 #include<iostream> #include<vector> using namespace std;class Solution{public:int climbStairs(int n){vector<int> memo(n+1,-1);memo[0]=1;memo[1]=1;for(int i=2;i<n;i++)memo[i]=memo[i-1]+memo[i-2];return memo[n];} };

leetcode:120

leetcode 64

每一步只能左移或者下移

9-3
leetcode 343整數(shù)分割



最優(yōu)子結(jié)構(gòu): 通過求子問題的最優(yōu)解,可以獲得原問題的最優(yōu)解




部分代碼如下:

在這里插入代碼片 //整數(shù)分割的問題 #include<iostream> #include<cassert> #include<vector> //記憶化搜索的關(guān)鍵是對訪問過的值進(jìn)行記錄,即用memo數(shù)組對結(jié)果進(jìn)行保存 using namespace std;class Solution{private:int max3(int a,int b,int c){return max(a,max(b,c));}//將n進(jìn)行分割,至少分割成兩部分,可以獲得的最大乘積 int breakInteger(int n){if(n==1)return 1;if(memo[n]!=-1)return memo[n];int res=-1;for(int i=1; i<=n-1; i++)//i+(n-i)res=max3(res,i*(n-i),i*breakInteger(n-i));memo[n]=res;return res; } public:int integerBreak(int n){assert(n>=2); memo=vector<int>(n+1,-1);return breakInteger(n);} };int main() {return 0; }

修改成動態(tài)規(guī)劃的問題

部分代碼如下:

//整數(shù)分割的問題 #include<iostream> #include<cassert> #include<vector> //記憶化搜索的關(guān)鍵是對訪問過的值進(jìn)行記錄,即用memo數(shù)組對結(jié)果進(jìn)行保存 using namespace std;class Solution{private:int max3(int a,int b,int c){return max(a,max(b,c));}} public:int integerBreak(int n){assert(n>=2); //將memo[i]進(jìn)行分割,至少分割成兩部分,可以獲得的最大乘積 vector<int> memo(n+1,-1);memo[1]=1;for(int i=1;i<n-1;i++)//求解memo[i]for(int j=1;j<=i-1;j++)//j+(i-j)memo[i]=max3(memo[i],j*(i-j),j*memo[i-j]);return memo(n);} };int main() {return 0; }

leetcode 279完全平方數(shù)



leetcode 91:解析方式

leetcode 62 不同路徑

leetcode 63 機(jī)器人 障礙物

9-4
leetcode 198 打家劫舍

房子不相鄰
價(jià)值最大



在這里插入代碼片//打家劫舍 #include<iostream> #include<vector>using namespace std;class Solution{private://memo[i]表示搶劫nums[i...n]所能獲得的最大收益vector<int> memo; //考慮搶劫nums[index...nums.size())這個(gè)范圍的所有房子 int tryRob(vector<int> &nums,int index){if(index>=nums.size())return 0;if(memo[index]!=-1)return memo[index];int res=0; for(i=index;i<nums.size();i++)res=max(res,nums[i]+tryRob(nums,i+2); memo[index]=res;return res; }public:int rob(vector<int>& nums){memo=vector<int>(nums.size(),-1);return tryRob(nums,0);}}; int main(){return 0;}

修改成動態(tài)規(guī)劃問題

在這里插入代碼片 //打家劫舍動態(tài)規(guī)劃 #include<iostream> #include<vector>using namespace std;class Solution{private:public:int rob(vector<int>& nums){int n=nums.size();if(n==0)return 0;//memo[i]表示搶劫nums[i...n-1]所能獲得的最大收益vector<int>memo(n,-1);memo[n-1]=nums[n-1];for(int i=n-2;i>=0;i--)//memo[i]for(int j=i; j<n;j++)memo[i]=max(memo[i],nums[j]+(j+2<n ? memo[j+2] : 0));return memo[0];} }; int main(){return 0;}

leetcode 213

leetcode 337



leetcode 309

設(shè)計(jì)一個(gè)自動交易算法

9-5 0-1背包問題


貪心算法?優(yōu)先放入平均價(jià)值最高的物品?


最優(yōu)解應(yīng)該為22>16貪心算法


在這里插入代碼片 //0-1背包問題 #include<iostream> #include<vector>using namespace std;class knapsack01{ private:vector<vector<int>> memo;//用[0...index]的物品,填充容積為c的背包的最大價(jià)值 int bestValue(const vector<int> &w, const vector<int> v, int index, int c){if(index<0 || c<=0)return 0;if(memo[index][c]!=-1)return memo[index][c];int res=bestValue(w,v,index-1,c);if(c>=w[index])res=max(v[index]+bestValue(w,v,index-1,c-w[index]); memo[index][c]=res;return res;}public:int knapsack01(const vector<int> &w, const vector<int> &v, int C){int n=w.size();memo=vector<vector<int>>(n,vector<int>(C+1,-1));return bestValve(w,v,n-1,c); } }; int main(){return 0;}

如何自頂向下解決該問題

橫軸為容量,縱軸為背包id

在這里插入代碼片 //0-1背包動態(tài)規(guī)劃問題 #include<iostream> #include<vector>using namespace std;class knapsack01{public:int knapsack01(const vector<int> &w, const vector<int> &v, int C){assert(w.size()==v.size()); int n=w.size();if(n==0 || C==0)return 0;vector<vector<int>> memo(n,vector<int>(C+1,-1));for(int j=0; j<=C; j++)memo[0][j]=(j>=w[0] ? v[0] : 0);for(int i=1; i<n; i++)for(int j=0; j<=C; j++){//0-i這些物品,背包為j memo[i][j]=memo[i-1][j];if(j>=w[i])memo[i][j]=max(memo[i][j],v[i]+memo[i-1][j-w[i]]) }return memo[n-1][C]; } }; int main(){return 0;}

9-6
0-1背包問題的優(yōu)化

在這里插入代碼片 //0-1背包動態(tài)空間復(fù)雜度的優(yōu)化問題 #include<iostream> #include<vector>using namespace std;class knapsack01{public:int knapsack01(const vector<int> &w, const vector<int> &v, int C){assert(w.size()==v.size()); int n=w.size();if(n==0 || C==0)return 0;vector<vector<int>> memo(2,vector<int>(C+1,-1));//將n改為2for(int j=0; j<=C; j++)memo[0][j]=(j>=w[0] ? v[0] : 0);for(int i=1; i<n; i++)for(int j=0; j<=C; j++){//0-i這些物品,背包為j memo[i%2][j]=memo[(i-1)%2][j];//對2取模,優(yōu)化空間。從n*c的復(fù)雜度變成了2*c的復(fù)雜度 if(j>=w[i])memo[i%2][j]=max(memo[i][j],v[i]+memo[(i-1)%2][j-w[i]]) }return memo[(i-1)%2][C]; } }; int main(){return 0;}


只考慮0的情況狀態(tài)

如果現(xiàn)在將1納入背包的狀態(tài),從右向左更新狀態(tài),比如5,在3的基礎(chǔ)上加1的為16,大于6則更新為16.依次類推,更新所有狀態(tài)。

在這里插入代碼片 //0-1背包動態(tài)空間復(fù)雜度的繼續(xù)優(yōu)化問題 #include<iostream> #include<vector>using namespace std;class knapsack01{public:int knapsack01(const vector<int> &w, const vector<int> &v, int C){assert(w.size()==v.size()); int n=w.size();if(n==0|| C==0)return 0;vector<int> memo(C+1,-1);//將n*c改為1*c for(int j=0; j<=C; j++)memo[j]=(j>=w[0] ? v[0] : 0);for(int i=1; i<n; i++)for(int j=C; j>=w[i]; j--){//0-i這些物品,背包為j //從n*c的復(fù)雜度變成了2*c的復(fù)雜度 memo[j]=max(memo[j],v[i]+memo[j-w[i]]);}return memo[C]; } }; int main(){return 0;}

0-1背包問題的變種

1 完全背包問題:每個(gè)物品可以無限使用
定容量,每個(gè)物品使用功能次數(shù)有最大值,對每個(gè)物品可以考慮使用二進(jìn)制進(jìn)行表示
2 多重背包問題:每個(gè)物品不止一個(gè),有num[i]個(gè)
3 多維費(fèi)用背包問題:要考慮物品的體積和重量兩個(gè)維度?
物品間加入更多約束
物品間可以互相排斥;也可以互相依賴

9-7
leetcode 416




//數(shù)組分割成相等的兩部分,其實(shí)也是變相的0-1背包問題,容量為sum/2 #include<iostream> #include<vector>using namespace std;class Solution{ private://memo[i][c]表示是否使用索引[0...i]的這些元素,是否可以完全填充一個(gè)容量為c的背包//-1 表示未計(jì)算,0表示不可以填充,1表示可以填充 vector<vector<int>> memo; //s使用nums[0...index],是否可以完全填充一個(gè)容量為sum的背包 bool tryPartition(const vector<int> &nums, int index, int sum){if(sum==0)return true;if(sum<0 || index<0)return false;if(memo[index][sum] !=-1)return memo[index][sum]==1;memo[index][sum]=(tryPartition(nums,index-1,sum) || tryPartition(nums,index-1,sum-nums[index])) ? 1 : 0 ;return memo[index][sum]==1;//等于1,則為true,反之為false } public:bool canPartition(vector<int>& nums){int sum =0;for(int i=0;i<nums.size();i++){assert(nums[i]>0);sum+=nums[i];}if(summ%2 !=0)return false;memo=vector<vector<int>>(nums.size(),vector<int>(sum/2)); //表示memo存儲了nums.size()這么多行,每一行是一個(gè)向量,并且每一行有sum/2這么多元素 tryPartition(nums,nums.size()-1,sum/2);} }; int main(){return 0; }

轉(zhuǎn)換成動態(tài)規(guī)劃問題

//數(shù)組分割成相等的兩部分,其實(shí)也是變相的0-1背包問題,容量為sum/2 //轉(zhuǎn)換成動態(tài)規(guī)劃問題 #include<iostream> #include<vector> #include<cassert> using namespace std;class Solution{public:bool canPartition(vector<int>& nums){int sum =0;for(int i=0;i<nums.size();i++){assert(nums[i]>0);sum+=nums[i];}if(summ%2 !=0)return false;int n=nums.size();int C=sum/2;vector<boo> memo(C+1,false);for(int i=-; i<=C;i++){memo[i]=(nums[0]==i);for(int i=1; i<n;i++)for(int j=C,j>=nums[i];j--)memo[j]=memo[j] || memo[j-nums[i]];return memo[C];}} }; int main(){return 0; }

練習(xí): leetcode 322 硬幣換現(xiàn)

leetcode 377 數(shù)組湊數(shù)

leetcode 474 01串


leetcode 139 字符串連接

leetcode 494 給定整數(shù)sum

9-8 9
leetcode 300最長上升子序列的長度

邊界情況:當(dāng)兩個(gè)元素是否相等的情況,這種情況他是否算在里面


初始化為1

根據(jù)狀態(tài)方程更新各個(gè)長度值

最后掃描一組的最大值


//最長上升子序列 //o(n^2)
#include
#include

using namespace std;

class Solution{

public:
int lengthOfLIS(vector& nums){

if(nums.size()==0)return 0;//memo[i] 表示nums[i]為結(jié)尾的最長上升子序列的長度 vector<int> memo(nums.size(), 1);for(int i=1; i<nums.size(),i++)for(int j=0; j<i; j++)if(nums[j]<nums[i])memo[i]=max(memo[i],1+memo[j]);int res=1;for(int i=0; i<nums.size(); i++)res=max(res,memo[i]);return res; } }; int main(){return 0;}

思考
leetcode: 376 升降輪流序列


最長公共子序列
longgest common sequence

圖論中最短路徑

總結(jié)

以上是生活随笔為你收集整理的玩转算法之面试第九章-动态规划的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。