題目輸入:
輸入格式:
5 //表示三角形的行數 接下來輸入三角形
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
在上面的數字三角形中尋找一條從頂部到底邊的路徑,使得路徑上所經過的數字之和最大。路徑上的每一步都只能往左下或 右下走。只需要求出這個最大和即可,不必給出具體路徑。 三角形的行數大於1小於等於100,數字爲 0 - 99。
輸出結果:30
看到這個三角輸入,首先需要用二維數組進行記錄,記爲D,那麼可以看出可以使用遞歸的方法進行求解,matrix[line][row]表示當前的位置,其中line表示行,row表示列,那麼最大值就應該是當前的值+下一行所對應的兩個值中的最大的那個,也就是maxSum(matrix, line + 1, row, len)和maxSum(matrix, line + 1, row + 1, len),其中maxSum()表示對二維數組某個位置開始從上網下的求和,len表示的也是行數,是終止條件,也就是當line==len的時候,遞歸到最後一行的時候結束。核心方法如下:
public static int maxSum(int[][] matrix, int line, int row, int len) {
if (line == len) {
return matrix[line][row];//當遞歸到最後一行直接返回
}
int cur = matrix[line][row];//保存當前位置的值
int x = maxSum(matrix, line + 1, row, len);//計算左兒子的值
int y = maxSum(matrix, line + 1, row + 1, len);//計算右兒子的值
return Math.max(x, y) + cur;//返回左右兩個兒子中最大的值+當前值
}
但是仔細看就可以看出來在從上往下進行遞歸的過程中計算存在大量重複,越往上計算的次數越多,所以我們就要換種思路,採用動態規劃來求解。
動態規劃:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
粘貼過來方便觀察,現在換種思路,從下往上推,初始化一個和最後一行一樣大小的數組,也將值複製給它,也就是初始化爲max=[4,5,2,6,5],首先我們找到max中相鄰兩個節點中最大的那個,接着加上相鄰兩個元素的父節點,例如最後一行4,5的父節點是2,那麼第一次循環後就得到max=[7,5,2,6,5],接着是5,2和7,繼續更新爲max=[7,12,2,6,5]...以此類推。這樣就可以不斷的向上一層進行循環,一直到第一層,最終max[0]位置的元素便是最大值,核心方法:
public static int maxSum2(int[][] matrix) {
int len = matrix.length - 1;
int[] max = matrix[len];//最後一層的元素
for (int i = len-1; i >= 0; i--) {//從倒數第二行開始循環,因爲最後一行我們已經初始化過了
for (int j = 0; j <= i; j++) {
//動態數組的值就是當前行的元素相鄰的最大值+上一層多對應的元素。
max[j] = Math.max(max[j], max[j + 1]) + matrix[i][j];
}
}
return max[0];
}
命令行輸入:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
完整代碼:
package arithmetic;
import java.util.Scanner;
/**
* Created by Hollake on 2019\7\19 0019 13:23.
*/
public class DpTwo {
public static void main(String[] args) {
// int[][] matrix = {{ 7}, { 3, 8}, { 8, 1, 0}, { 2, 7, 4, 4}, { 4, 5, 2, 6, 5}};
Scanner sc = new Scanner(System.in);
while ( sc.hasNext() ) {
int line = sc.nextInt();
int[][] matrix = new int[line][line];
for (int i = 0; i < line; i++) {
for (int j = 0; j < i + 1; j++) {
matrix[i][j] = sc.nextInt();
}
}
System.out.println(maxSum(matrix, 0, 0, line-1));
System.out.println(maxSum2(matrix));
}
}
// 遞歸
public static int maxSum(int[][] matrix, int line, int row, int len) {
if (line == len) {
return matrix[line][row];//當遞歸到最後一行直接返回
}
int cur = matrix[line][row];//保存當前位置的值
int x = maxSum(matrix, line + 1, row, len);//計算左兒子的值
int y = maxSum(matrix, line + 1, row + 1, len);//計算右兒子的值
return Math.max(x, y) + cur;//返回左右兩個兒子中最大的值+當前值
}
// 動態規劃
public static int maxSum2(int[][] matrix) {
int len = matrix.length - 1;
int[] max = matrix[len];//最後一層的元素
for (int i = len-1; i >= 0; i--) {//從倒數第二行開始循環,因爲最後一行我們已經初始化過了
for (int j = 0; j <= i; j++) {
//動態數組的值就是當前行的元素相鄰的最大值+上一層多對應的元素。
max[j] = Math.max(max[j], max[j + 1]) + matrix[i][j];
}
}
return max[0];
}
}