【lLeetCode】動歸
阿新 • • 發佈:2022-03-10
一維
70 爬樓梯E
198 小偷E
- 解法:
dp[i] = Math.max(dp[i-1], dp[i-2]+nums[i-1]);
413 等差數列劃分M
- 題意:找出陣列中等差數列的數量(最少為3個元素算一個等差數列)
- 解法:
- 差分:
for(int i = 2; i < n; ++i){ if(nums[i-1] - nums[i] == d){ t++; }else{ d = nums[i-1] - nums[i]; t = 0; } ans += t;
- 滑動視窗:
for(int i = 2; i < n; ++i){ int d = nums[i] - nums[i-1]; if(d == pred){ L++; //滑動視窗增加 }else{ res += (L-1)*(L-2)/2; //規律 L = 2; //滑動視窗重新設為2 pred = d; } } //對最後一組滑動視窗再計算一次 res += (L-1)*(L-2)/2;
- 動態規劃:
for(int i = 2; i < n; ++i){
if(nums[i] - nums[i-1] == nums[i-1] - nums[i-2]){
dp[i] = dp[i-1] + 1; //等差數列相關的狀態轉移方程
res += dp[i];
}
}
二維
64 最小路徑和M
- 題意:非負二維陣列,從左上到右下角的最小路徑和
- 解法:
-
動態規劃:
狀態轉移方程:dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + grid[i][j];
但是i=0和j=0的時候要判斷 -
動態規劃(二維變一維):
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
if(i == 0 && j == 0){
dp[j] = grid[i][j];
}else if(i == 0){
dp[j] = dp[j-1] + grid[i][j];
}else if(j == 0){
dp[j] = dp[j] + grid[i][j];
}else{
dp[j] = Math.min(dp[j], dp[j-1]) + grid[i][j];
}
}
}
542 01矩陣M
- 題意:輸出由01組成的矩陣每個元素與0的距離(0是0,1要看離它最近的0)
- 解法:
- bfs:讓所有的0入隊,遍歷一圈找到離它們最近的1入隊,並dist++,
//bfs
while(!queue.isEmpty()){
int[] cell = queue.poll();
int x = cell[0];
int y = cell[1];
for(int[] di : dirs){
int nx = x + di[0];
int ny = y + di[1];
if(nx >= 0 && ny >= 0 && nx < m && ny < n && !visited[nx][ny]){
if(mat[nx][ny] != 0){
dist[nx][ny] = dist[x][y] + 1;
visited[nx][ny] = true;
queue.offer(new int[]{nx, ny});
}
}
}
}
- 動態規劃:從左上右上右下左下四種方向,設定移動方向,比較距離最小值。
//左上。即後來的dist值與左邊和上邊的dist值進行比較。
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
if(i-1 >= 0){
dist[i][j] = Math.min(dist[i][j], dist[i-1][j] + 1);
}
if(j-1 >= 0){
dist[i][j] = Math.min(dist[i][j], dist[i][j-1] + 1);
}
}
}
221 最大正方形M
- 題意:找出01矩陣中包含的最大的正方形,輸出面積
- 思路:
- 暴力法:找到一個1就當做正方形的左上角,在剩餘可圍成的最大矩形中,先判斷斜線上的元素是否為1,若為1,則判斷該元素行和列上的元素是否為1,都為1則記錄邊長
//遍歷到1將其作為正方形左上角
if(matrix[i][j] == '1'){
res = Math.max(res, 1);
//還剩下的最大矩陣邊長reMain
int reMain = Math.min(m-i, n-j);
//遍歷斜線
for(int k = 1; k < reMain; ++k){
boolean flag = true;
if(matrix[i+k][j+k] == '0'){
break;
}
//當斜線上的元素符合時,再檢查該處行和列上的元素
for(int x = 0; x < k; ++x){
if(matrix[i+x][j+k] == '0' || matrix[i+k][j+x] == '0'){
flag = false;
break;
}
}
//每多在斜線上前進一格並判斷成功,記錄res
if(flag == true){
res = Math.max(k+1, res);
}else{
break;
}
- 動態規劃:
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
//當前位置為‘0’
if(matrix[i][j] == '0'){
dp[i][j] = 0;
}else{
if(i == 0 || j == 0){
dp[i][j] = 1;
}else{
//狀態轉移方程
dp[i][j] = Math.min(Math.min(dp[i-1][j], dp[i-1][j-1]), dp[i][j-1]) + 1;
}
}
res = Math.max(dp[i][j], res);
}
279 完全平方數M
- 題意:等價於給定若干個數字,每個數字可以被使用無限次,求能湊出n使用的數字最少個數
- 沒有限制數字只能用一次,所以是完全揹包問題
- 動歸:一維
for(int i = 1; i <= n; ++i){
for(int j = 1; j*j < i; ++j){
dp[i] = Math.min(dp[i], dp[i-j*j] + 1);
}
}
+ 動歸:**二維完全揹包**
***
### 91 解碼方法M
***