LeetCode 70 爬樓梯
題目
假設你正在爬樓梯。需要 n階你才能到達樓頂。
每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?
注意:給定 n 是一個正整數。
輸入: 2
輸出: 2
解釋: 有兩種方法可以爬到樓頂。
1. 1 階 + 1 階
2. 2 階
思路
F(n)=F(n-1)+F(n-2) 斐波那契數列的應用
代碼
#include <iostream>
#include <vector>
using namespace std;
//動態規劃解
class Solution {
public:
int climbStairs(int n) {
vector<int> memo;
memo = vector<int>(n+1,-1);
memo[1] = 1;
memo[2] = 2;
for(int i=3; i<=n; i++)
memo[i] = memo[i-1] + memo[i-2];
return memo[n];
}
};
int main()
{
return 0;
}
LeetCode 120 三角形最小路徑和
題目
給定一個三角形,找出自頂向下的最小路徑和。每一步只能移動到下一行中相鄰的結點上。
相鄰的結點 在這裏指的是 下標 與 上一層結點下標 相同或者等於 上一層結點下標 + 1 的兩個結點。
例如,給定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自頂向下的最小路徑和爲11(即,2+3+5+1= 11)。
思路
從倒二行起,從下至上,從左至右,依次更新三角形數組上的值
更新值爲下一層相鄰兩個數和的最小值。那麼triangle[i][j]就表示從點[(i,j)開始自頂向下的最小路徑和
代碼
#include <iostream>
#include <vector>
using namespace std;
//動態規劃解
class Solution {
public:
int minimumTotal(vector<vector<int> >& triangle) {
int n = triangle.size();
if(n==0) return 0;
//從倒二行開始更新數組,數組更新值應該等於該數與其下一層相鄰兩個數和的最小值
for(int i=n-2; i>=0; i--)
for( int j=0; j<triangle[i].size(); j++)
triangle[i][j] = min(triangle[i][j]+triangle[i+1][j],triangle[i][j]+triangle[i+1][j+1]);
return triangle[0][0];
}
};
int main()
{
return 0;
}
LeetCode 64 最小路徑和
題目
給定一個包含非負整數的 m x n 網格,請找出一條從左上角到右下角的路徑,使得路徑上的數字總和爲最小。
說明:每次只能向下或者向右移動一步。
示例:
輸入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
輸出: 7
解釋: 因爲路徑 1→3→1→1→1 的總和最小。
思路
從右至左,從底至上更新grid的每個值
grid的值代表的是該點移動到右下角點的最小路徑和
如果是最後一行,只能向右移動,grid[i][j] = grid[i][j]+grid[i][j+1]
如果是最後一列,只能向下移動,grid[i][j] = grid[i][j]+grid[i+1][j]
當可以向下走或者向右走,尋找最短路徑:grid[i][j] = min(grid[i][j]+grid[i][j+1],grid[i][j]+grid[i+1][j]);
代碼
//動態規劃解
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
//思路:從右至左,從底至上更新grid的每個值
//grid的值代表的是該點移動到右下角點的最小路徑和
int n = grid.size();
if(n==0) return 0;
int m = grid[0].size();
for(int i=n-1; i>=0; i--) //從最後一行開始更新
{
for(int j=m-1; j>=0;j--) //從最後一列開始更新
{
//判斷當前數是否可以向右向下走
if(i==n-1 && j==m-1)
continue;
else if(i==n-1) //最後一行,只能向右走
grid[i][j] += grid[i][j+1];
else if(j==m-1) //最後一列,只能向下走
grid[i][j] += grid[i+1][j];
else //可以向下,也可以向右走,尋找最短路徑
grid[i][j] = min(grid[i][j]+grid[i][j+1],grid[i][j]+grid[i+1][j]);
}
}
return grid[0][0];
}
};
LeetCode 279 完全平方數
題目
給定正整數 n,找到若干個完全平方數(比如 1, 4, 9, 16, ...)使得它們的和等於 n。
你需要讓組成和的完全平方數的個數最少。
示例 1:
輸入: n = 12
輸出: 3
解釋: 12 = 4 + 4 + 4.
示例 2:
輸入: n = 13
輸出: 2
解釋: 13 = 4 + 9.
思路
使用memo數組保存組成和爲i的完全平方數的最少個數。
想要計算每個memo[i],找到所有0,i之間的完全平方數x memo[i]=min(1+memo[i-x])
代碼
#include <iostream>
#include <vector>
using namespace std;
//動態規劃解
class Solution {
public:
int numSquares(int n) {
vector<int> memo(n+1,0); //memo中存着組成n和的完全平方數的最少個數。
memo[1] = 1;
//獲取每個memo[i]
for(int i=2; i<=n; i++)
{
memo[i] = 1+memo[i-1]; //第一種劃分方式是劃分成1和 i-1(i-1繼續劃分)
for(int j=1; i-j*j>=0 ; j++) //將i劃分爲 j*j i-j*j
{
if(i-j*j==0) //說明這個數是完全平方數
{
memo[i]=1;
continue;
}
memo[i] =min(memo[i],1+ memo[i-j*j]);
}
}
return memo[n];
}
};
int main()
{
return 0;
}
LeetCode 300 最長上升子序列
題目
給定一個無序的整數數組,找到其中最長上升子序列的長度。
示例:
輸入: [10,9,2,5,3,7,101,18]
輸出: 4
解釋: 最長的上升子序列是 [2,3,7,101],它的長度是 4。
說明:
可能會有多種最長上升子序列的組合,你只需要輸出對應的長度即可。
思路
使用數組memo:memo[i]中存儲的是以nums[i]結尾的最長上升子序列長度
初始化:每個只有自身的上升子序列長度都爲1
對於當前的數字nums[i],遍歷nums[i]前面所有的數,找到一個比nums[i]小的數,說明nums[i]可以跟在找到的數後面
memo[i]=找到所有可能nums[i]能跟在後面的值j memo[j]的最大值+1
代碼
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
if(n==0) return 0;
vector<int> memo(n,1);//memo[i]中存儲的是以nums[i]結尾的最長上升子序列長度
for(int i=1; i<n; i++)
{
//遍歷nums[i]前面所有的數,找到一個比nums[i]小的數,nums[i]可以跟在找到的數後面
//找到所有可能結果的最大值
for(int j=0; j<i; j++)
{
if(nums[i] > nums[j])
memo[i] = max(memo[i],memo[j]+1);
}
}
int res = 0;
for(int i=0; i<n; i++)
res = max(res,memo[i]);
return res;
}
};
LeetCode 322
給定不同面額的硬幣 coins 和一個總金額 amount。
編寫一個函數來計算可以湊成總金額所需的最少的硬幣個數。
如果沒有任何一種硬幣組合能組成總金額,返回-1。
示例1:
輸入: coins = [1, 2, 5], amount = 11
輸出: 3
解釋: 11 = 5 + 5 + 1
示例 2:
輸入: coins = [2], amount = 3
輸出: -1
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int Max = amount + 1;
int n = coins.size();
if(n==0) return -1;
if(amount==0) return 0;
//湊成i所需的少的硬幣個數。
vector<int> memo(amount+1,Max);
memo[0] = 0;
for(int i=0; i<=amount; i++)
{
//對於當前金額i memo[i]=min(memo[i-coins[j]+1)
for(int j=0; j<n; j++)
{
if(i>=coins[j])
{
memo[i] = min(memo[i],memo[i-coins[j]] + 1);
}
}
}
return memo[amount]>amount?-1:memo[amount];
}
};
洛谷上的一道經典動態規劃問題 過河卒
思路
使用一個memo數組,存儲從座標(i,j)到達B點的路徑條數
如果一個點是馬所在的點或者馬的控制點,那麼該點無法到達B,memo[i][j]=0
對於每一個不是馬所在的點或者馬的控制點,從下至上,從右至左依次計算memo[i][j]:
如果點(i,j)是最後一行的點,那麼只能往右走,memo[i][j]=memo[i][j+1]
如果點(i,j)是最後一列的點,那麼只能往下走,memo[i][j]=memo[i+1][j]
其他點,可以向下或者向右走,memo[i][j] = memo[i+1][j]+memo[i][j+1];
代碼
bool inArea(int x, int y, int Bx, int By )
{
return x>=0 && y>=0 && x<=Bx && y<=By;
}
int main()
{
int Bx,By;
int Mx,My;
cin>>Bx>>By>>Mx>>My;
vector<vector<long long> > memo(Bx+1,vector<long long>(By+1,-1));
//先將馬所佔位置置爲0
memo[Mx][My] = 0;
for(int i= Mx-2; i<=Mx+2; i++)
{
if(i==Mx) continue;
if(i==Mx-2 || i==Mx+2 )
{
if(inArea(i,My-1,Bx,By))
memo[i][My-1] = 0;
if(inArea(i,My+1,Bx,By))
memo[i][My+1] = 0;
}else
{
if(inArea(i,My-2,Bx,By))
memo[i][My-2] = 0;
if(inArea(i,My+2,Bx,By))
memo[i][My+2] = 0;
}
}
//先算出最後一行的全部解
memo[Bx][By] = 1;
for(int i=By-1; i>=0; i--)
{
if(memo[Bx][i]!=0)
memo[Bx][i] = memo[Bx][i+1];
}
//遍歷每一行
for(int i=Bx-1; i>=0; i--)
{
for(int j=By; j>=0; j--)
{
if(memo[i][j]!=0)
{
if(j==By)
{
memo[i][j] = memo[i+1][j];
}else
{
memo[i][j] = memo[i+1][j]+memo[i][j+1];
}
}
}
}
cout<<memo[0][0]<<endl;
return 0;
}