题意:寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或右下走。
解题思路:
二维数组存放数字三角形;
D[r][j]:第 r 行第 j 个数字(r,j 从 1 开始);
MaxSum(r,j):从 D(r,j)到底边的各条路径中,最佳路径的数字之和。
问题:求 MaxSum(1,1)。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class Main {
private static final int MAX = 101;
private static int D[][] = new int[MAX][MAX];
private static int maxSum[][] = new int[MAX][MAX];
private static int N;
// /**
// * 超时代码,因为有大量的重复计算。时间复杂度:2^n
// */
// private static int MaxSum(int i, int j) {
// if (i == N) {
// return D[i][j];
// }
// int x = MaxSum(i + 1, j);
// int y = MaxSum(i + 1, j + 1);
// return Math.max(x, y) + D[i][j];
// }
/**
* 记忆递归型动归程序,时间复杂度:n^2
* 每算出一个 MaxSum(r,j) 就保存起来,下次用到其值时,直接取用,则可以避免重复计算
*/
private static int MaxSum(int i, int j) {
if (maxSum[i][j] != 0) {
return maxSum[i][j];
}
if (i == N) {
maxSum[i][j] = D[i][j];
} else {
int x = MaxSum(i + 1, j);
int y = MaxSum(i + 1, j + 1);
maxSum[i][j] = Math.max(x, y) + D[i][j];
}
return maxSum[i][j];
}
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
N = (int) in.nval;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= i; j++) {
in.nextToken();
D[i][j] = (int) in.nval;
}
}
out.println(MaxSum(1, 1));
}
out.flush();
}
}
以下为优化方案:
优化:将递归转换为递推!!!
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class Main {
private static final int MAX = 101;
private static int D[][] = new int[MAX][MAX];
private static int maxSum[][] = new int[MAX][MAX];
private static int N;
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
N = (int) in.nval;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= i; j++) {
in.nextToken();
D[i][j] = (int) in.nval;
}
}
System.arraycopy(D[N], 1, maxSum[N], 1, N);
for (int i = N - 1; i >= 1; i--) {
for (int j = 1; j <= i; j++) {
maxSum[i][j] = Math.max(maxSum[i + 1][j], maxSum[i + 1][j + 1]) + D[i][j];
}
}
out.println(maxSum[1][1]);
}
out.flush();
}
}
进一步优化:空间优化
没必要用二维 maxSum 数组存放每一个 MaxSum(r,j),只要从底层一行行向上递推,那么只要一堆数组 maxSum[100] 即可,即只要存储一行的 MaxSum 值就可以。
更进一步优化:空间优化
进一步考虑,连 maxSum 数组都可以不要,直接用 D 的第 n 行代替 maxSum 即可。节省空间,时间复杂度不变。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class Main {
private static final int MAX = 101;
private static int D[][] = new int[MAX][MAX];
private static int maxSum[];
private static int N;
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
N = (int) in.nval;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= i; j++) {
in.nextToken();
D[i][j] = (int) in.nval;
}
}
maxSum = D[N]; // maxSum 指向第 n 行
for (int i = N - 1; i >= 1; i--) {
for (int j = 1; j <= i; j++) {
maxSum[j] = Math.max(maxSum[j], maxSum[j + 1]) + D[i][j];
}
}
out.println(maxSum[1]);
}
out.flush();
}
}