Redraiment 是走梅花桩的高手。现在,地上有 n个梅花桩排成一排,从前到后高度依次为 h1,h2,…,hn
Redraiment 可以任选一个梅花桩开始,向后跳到任意一个比当前高度高的梅花桩上。
求 Redraiment 最多可以跳过多少个梅花桩。
输入描述: 第一行输入一个整数 n(1≦n≦200) 代表梅花桩的数量。 第二行入n个整数, h1,h2,…,hn(1≦hi≦350)代表每一个梅花桩的高度。
输出描述: 输出一个正整数,代表 Redraiment 最多可以跳过多少个梅花桩。
输入:
6 2 5 1 5 4 5
输出:
3
说明:
在这个样例中,其中一个最优的选择是,从第一个桩子起跳,最多可以跳三个梅花桩,使用橙色加粗标识:{2,5,1,5,4,5}。 另外一种最优选择是,从第三个桩子起跳,最多也可以跳三个梅花桩,使用橙色加粗标识:{2,5,1,5,4,5}。
解法一:记负均正法
import java.util.*;
public class Main{
public static void main(String[] arg) {
Scanner scan = new Scanner(System.in);
while (scan.hasNext()) {
scan.nextLine();
String[] input1 = scan.nextLine().split(" ");
int[] intArr = Arrays.stream(input1).mapToInt(Integer::parseInt).toArray();
int[] k=new int[intArr.length];
for(int j=1;j<intArr.length;j++){
for(int i=0;i<j;i++){
if(intArr[i]<intArr[j]){
k[j]=Math.max(k[j],k[i]+1);
}
}
}
Arrays.sort(k);
System.out.println(k[k.length-1]+1);
}
}
}
解法二:动态规划法
动态规划思路:
-
定义状态:
-
dp[i]
表示以第i
个梅花桩结尾的最长递增子序列的长度。
-
-
初始化:
-
每个
dp[i]
初始化为 1,因为至少可以单独选择自己。
-
-
状态转移:
-
对于每个
i
,遍历所有j < i
:-
如果
h[j] < h[i]
,则dp[i] = max(dp[i], dp[j] + 1)
。 -
这表示如果可以从
j
跳到i
,则更新dp[i]
。
-
-
-
结果:
-
dp
数组中的最大值就是答案。
-
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] heights = new int[n];
for (int i = 0; i < n; i++) {
heights[i] = scanner.nextInt();
}
int[] dp = new int[n];
Arrays.fill(dp, 1); // 初始化为 1
int maxLen = 1; // 至少可以跳 1 个梅花桩
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (heights[j] < heights[i]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
maxLen = Math.max(maxLen, dp[i]);
}
System.out.println(maxLen);
}
}
为什么更新 dp[i]
而不是 dp[j]
?
动态规划的核心是状态定义和状态转移。在这里:
-
状态定义:
dp[i]
表示以第i
个梅花桩结尾的最长递增子序列的长度。 -
状态转移:对于每个
i
,我们需要找到所有j < i
且heights[j] < heights[i]
的j
,然后用dp[j] + 1
来更新dp[i]
。
示例:
输入:
6 2 5 1 5 4 5
DP 数组填充过程:
-
dp = [1, 1, 1, 1, 1, 1]
(初始化) -
i=1
(高度 5):-
j=0
(高度 2):2 < 5
→dp[1] = max(1, dp[0]+1=2)
→dp = [1, 2, 1, 1, 1, 1]
-
-
i=2
(高度 1):-
j=0
(高度 2):2 > 1
→ 跳过 -
j=1
(高度 5):5 > 1
→ 跳过 -
dp[2]
保持 1 →dp = [1, 2, 1, 1, 1, 1]
-
-
i=3
(高度 5):-
j=0
(高度 2):2 < 5
→dp[3] = max(1, dp[0]+1=2)
→dp = [1, 2, 1, 2, 1, 1]
-
j=1
(高度 5):5 == 5
→ 跳过 -
j=2
(高度 1):1 < 5
→dp[3] = max(2, dp[2]+1=2)
→ 保持 2
-
-
i=4
(高度 4):-
j=0
(高度 2):2 < 4
→dp[4] = max(1, dp[0]+1=2)
→dp = [1, 2, 1, 2, 2, 1]
-
j=1
(高度 5):5 > 4
→ 跳过 -
j=2
(高度 1):1 < 4
→dp[4] = max(2, dp[2]+1=2)
→ 保持 2 -
j=3
(高度 5):5 > 4
→ 跳过
-
-
i=5
(高度 5):-
j=0
(高度 2):2 < 5
→dp[5] = max(1, dp[0]+1=2)
→dp = [1, 2, 1, 2, 2, 2]
-
j=1
(高度 5):5 == 5
→ 跳过 -
j=2
(高度 1):1 < 5
→dp[5] = max(2, dp[2]+1=2)
→ 保持 2 -
j=3
(高度 5):5 == 5
→ 跳过 -
j=4
(高度 4):4 < 5
→dp[5] = max(2, dp[4]+1=3)
→dp = [1, 2, 1, 2, 2, 3]
-
-
maxLen
为dp
数组的最大值 3。
输出:3
复杂度分析:
-
时间复杂度:O(n²),因为有两层嵌套循环。
-
空间复杂度:O(n),用于存储
dp
数组。