文章目錄
- 動態規劃
- 動態規劃的本質
- 動態規劃使用場景
- 例題1:斐波那契數列
- 例題2. 變態跳臺階
- 變形1:一次只能跳1級或者2級(類似于斐波那契數列)
- 變形2:矩形覆寫
- 例題3:最大連續子陣列和
- 例題4:拆分詞句
- 例題5.三角矩陣
- 例題6.不同路徑
- 例題7:不同路徑2
- 例題8.帶權值的最小路徑和
- 例題9.背包問題2
- 例題10.回文串分割
- 例題11.編輯距離
動態規劃
動態規劃是分治思想的延伸,大事化小小事化無
動態規劃具備的特點:
1.把原來的問題分解成幾個相似的子問題
2.所有的子問題都只需要解決一次
3.存盤子問題的解
動態規劃的本質
動態規劃的本質,是對問題狀態的定義和狀態轉移方程的定義
從以下角度考慮:
1.狀態定義(定義的狀態一定要形成遞推關系)
2.狀態間的轉移方程定義
3.狀態的初始化
4.回傳結果
動態規劃使用場景
最大值/最小值,可不可行,是不是,方案個數
例題1:斐波那契數列
LeetCode:斐波那契數列
分析問題程序:
問題:數列第N項的值
狀態F(i):數列第i項的值
轉移方程:F(i)=F(i-1)+F(i-2)
初始狀態:F(0)=0,F(1)=1
回傳:F(n)
class Solution {
public:
//遞回
int fib(int n) {
if(n<=1){
return n;
}
if(n==2){
return 1;
}
return fib(n-1)%1000000007+fib(n-2)%1000000007;
}
//動態規劃-記錄每個子問題的解
int fib(int n){
if(n==0){
return 0;
}
vector<int> v(n+1,0);
v[1]=1;//初使狀態
for(int i=2;i<=n;i++){
v[i]=v[i-1]%1000000007+v[i-2]%1000000007;//轉移方程
}
return v[n]%1000000007;
}
//動態規劃-不記錄每個子問題解
int fib(int n){
if(n<=1){
return n;
}
int a=0;
int b=1;
int num;
for(int i=2;i<=n;i++){
num=a%1000000007+b%1000000007;
a=b;
b=num;
}
return num%1000000007;
}
};
例題2. 變態跳臺階
牛客:變態跳臺階
問題:跳上n級臺階的方法個數
狀態F(i):跳上i級臺階的方法個數
轉移方程:F(i)=F(0)+F(1)+F(2)+…+F(i-1);
F(i-1):F(i-2)+F(i-3)+…+F(0);
F(i)=F(i-1)+F(i-1)=2*F(i-1);
初使狀態:F(1)=1
回傳:F(n)
class Solution {
public:
int jumpFloorII(int number) {
if(number==0)
return 0;
int ret=1;
for(int i=2;i<=number;i++){
ret=ret*2;//轉移方程
}
return ret;
}
};
變形1:一次只能跳1級或者2級(類似于斐波那契數列)
狀態轉移方程:F(i)=F(i-1)+F(i-2)
變形2:矩形覆寫
牛客:矩形覆寫
狀態轉移方程:F(i)=F(i-1)+F(i-2)
class Solution {
public:
int rectCover(int number) {
if(number<=1){
return number;
}
int a=1;
int b=1;
int ret;
for(int i=2;i<=number;i++){
ret=a+b;
a=b;
b=ret;
}
return ret;
}
};
例題3:最大連續子陣列和
牛客:最大連續子陣列和

問題:陣列的最大連續和
狀態:F(i)
轉移方程:F(i)=max(F(i-1)+a[i],a[i])
初使狀態F(0)=a[0]
回傳值:max(F(i))
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
if(array.empty()){
return 0;
}
vector<int> v(array.size(),0);
v[0]=array[0];
int ret=v[0];
for(int i=1;i<array.size();i++){
v[i]=max(v[i-1]+array[i],array[i]);//狀態轉移方程
ret=max(ret,v[i]);
}
return ret;
}
};
例題4:拆分詞句
問題:單詞是否可以成功分割
狀態:F(i)
轉移方程:F(i):j<i&&[j+1,i]是否可以在詞典中找到
回傳結果:F(s.size())
class Solution {
public:
/*bool wordBreak(string s, unordered_set<string> &dict) {
vector<bool> v(s.size() + 1);
for (int i = 1; i <= s.size(); i++){
if (dict.find(s.substr(0, i)) != dict.end()){
v[i] = true;
continue;
}
for (int j = i - 1; j>0; j--){
if (v[j] && (dict.find(s.substr(j, i)) != dict.end())){
v[i] = true;
break;
}
}
}
return v[s.size()];
}*/
bool wordBreak(string s, unordered_set<string> &dict) {
vector<bool> v(s.size() + 1);
v[0] = true;
for (int i = 1; i <= s.size(); i++){
for (int j = i - 1; j>=0; j--){
if (v[j] && (dict.find(s.substr(j, i)) != dict.end())){
v[i] = true;
break;
}
}
}
return v[s.size()];
}
};
例題5.三角矩陣
牛客:三角矩陣
問題:從(0,0)到達最后一行的最小路徑和
狀態F(i,j):從(0,0)到達(i,j)的最小路徑和
F(i,j):min(F(i-1,j),F(i-1,j-1))+a[i][j]
每一行第一列,最后一列只有一條路到達
F(i,0):F(i-1,0)+a[i][0]
F(i,i):F(i-1,i-1)+a[i][i]
初使狀態:F(0,0)=a[0][0]
回傳結果:max{F(row-1,j)}
class Solution {
public:
int minimumTotal(vector<vector<int> > &triangle) {
if(triangle.empty()){
return 0;
}
vector<vector<int>> vv(triangle);
int row=triangle.size();
int col=triangle[0].size();
for(int i=1;i<row;i++){
for(int j=0;j<i+1;j++){
if(j==0){
vv[i][j]=vv[i-1][j]+triangle[i][j];
}
else if(j==i){
vv[i][j]=vv[i-1][j-1]+triangle[i][j];
}
else{
vv[i][j]=min(vv[i-1][j-1],vv[i-1][j])+triangle[i][j];
}
}
}
int row_vv=row-1;
int ret=vv[row_vv][0];
for(int i=0;i<vv[row_vv].size();i++){
ret=min(ret,vv[row_vv][i]);
}
return ret;
}
};
例題6.不同路徑
LeetCode:不同路徑
問題:從(0,0)到達(i,j)的路徑和
狀態F(i,j):從(0,0)到達(i,j)的路徑個數
轉移方程:F(i,j)=F(i-1,j)+F(i,j-1)
初使狀態:F(0,0)=1
回傳結果:F(i,j)
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> vv(m,vector<int>(n));
for(int i=0,j=0;j<n;j++){
vv[i][j]=1;
}
for(int i=0,j=0;i<m;i++){
vv[i][j]=1;
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
if(i-1<0){
vv[i][j]=vv[i][j-1];
}
else if(j-1<0){
vv[i][j]=vv[i-1][j];
}
else{
vv[i][j]=vv[i-1][j]+vv[i][j-1];
}
}
}
return vv[m-1][n-1];
}
};
例題7:不同路徑2
LeetCode:不同路徑II
狀態F(i,j):從(0,0)到(i,j)路徑個數
F(i,j):
if(obstacle[i][j]==1)
F(i,j)=0
else
F(i,j)=F(i,j-1)+F(i-1,j)
初使狀態:
if(obstacle[i][0]==0&&obstacle[j][0]==0&&j<i)
F(i,0)=1;
if(obstacle[0][i]==0&&obstacle[0][j]==0&&j<i)
F(0,i)=1;
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
if(obstacleGrid.empty()){
return 0;
}
int row=obstacleGrid.size();
int col=obstacleGrid[0].size();
vector<vector<int>> vv(row,vector<int>(col,0));
for(int i=0;i<row;i++){
if(obstacleGrid[i][0]==0){
vv[i][0]=1;
}
else{
break;
}
}
for(int i=0;i<col;i++){
if(obstacleGrid[0][i]==0){
vv[0][i]=1;
}
else{
break;
}
}
for(int i=1;i<row;i++){
for(int j=1;j<col;j++){
if(obstacleGrid[i][j]==1){
vv[i][j]=0;
}else{
vv[i][j]=vv[i-1][j]+vv[i][j-1];
}
}
}
return vv[row-1][col-1];
}
};
例題8.帶權值的最小路徑和
牛客:帶權值的最小路徑和
狀態F(i,j)
狀態方程:F(i,j)=min(F(i-1,j),F(i,j-1))+F(i,j)
初使值:F(0,0)=grid[0][0]
回傳值:F(row-1,col-1)
class Solution {
public:
/**
*
* @param grid int整型vector<vector<>>
* @return int整型
*/
int minPathSum(vector<vector<int> >& grid) {
// write code here
int row=grid.size();
int col=grid[0].size();
vector<vector<int>> vv(grid);
for(int i=1;i<row;i++){
vv[i][0]=vv[i-1][0]+vv[i][0];
}
for(int j=1;j<col;j++){
vv[0][j]=vv[0][j-1]+vv[0][j];
}
for(int i=1;i<row;i++){
for(int j=1;j<col;j++){
vv[i][j]=min(vv[i-1][j],vv[i][j-1])+vv[i][j];
}
}
return vv[row-1][col-1];
}
};
例題9.背包問題2
背包問題2

class Solution {
public:
/**
* @param m: An integer m denotes the size of a backpack
* @param A: Given n items with size A[i]
* @param V: Given n items with value V[i]
* @return: The maximum value
*/
int backPackII(int m, vector<int> &A, vector<int> &V) {
// write your code here
int n=A.size();
if(n==0||m==0)
return 0;
vector<vector<int>> maxV(n+1,vector<int>(m+1,0));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;++j){
if(A[i-1]<=j){
maxV[i][j]=max(maxV[i-1][j],maxV[i-1][j-A[i-1]]+V[i-1]);
}
else{
maxV[i][j]=maxV[i-1][j];
}
}
}
return maxV[n][m];
}
};
例題10.回文串分割
回文串分割
class Solution {
public:
/**
*
* @param s string字串
* @return int整型
*/
bool ispal(string s,int start,int end){
while(start<end){
if(s[start]!=s[end])
return false;
++start;
--end;
}
return true;
}
int minCut(string s) {
vector<int> v(s.size()+1);
for(int i=1;i<=s.size();i++){
v[i]=i-1;
}
for(int i=2;i<=s.size();i++){
if(ispal(s,0,i-1)){
v[i]=0;
continue;
}
for(int j=1;j<i;j++){
if(ispal(s,j,i-1)){
v[i]=min(v[i],v[j]+1);
}
}
}
return v[s.size()];
}
};
例題11.編輯距離
編輯距離

問題:word1轉成word2的最小操作次數
狀態F(i,j):word1前i個字符轉成Word2的前j個字符的最小操作次數
轉移方程:F(i,j):min(F(i-1,j-1),F(i-1,j),F(i,j-1))+1
class Solution {
public:
/**
*
* @param word1 string字串
* @param word2 string字串
* @return int整型
*/
int minDistance(string word1, string word2) {
// write code here
int len1=word1.length();
int len2=word2.length();
vector<vector<int>> minD(len1+1,vector<int>(len2+1));
for(int i=0;i<=len2;++i)
minD[0][i]=i;
for(int i=0;i<=len1;++i){
minD[i][0]=i;
}
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;++j){
minD[i][j]=min(minD[i][j-1],minD[i-1][j])+1;
if(word1[i-1]==word2[j-1])
minD[i][j]=min(minD[i][j],minD[i-1][j-1]);
else
minD[i][j]=min(minD[i][j],minD[i-1][j-1]+1);
}
}
return minD[len1][len2];
}
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/279344.html
標籤:其他
上一篇:2021年大資料Spark(三十四):Spark Streaming概述
下一篇:案例分享:Qt出版社書籍配套U盤資源播放器軟體定制(腳本關聯播放器與資源檔案,播放器,兼容win7,win10和mac)
