描述
给定一个字符串 S ,定义三种有价值的字符串: A = "nico" ,B = "niconi" , C = "niconiconi"
其中,字符串 A 的价值为 a, 字符串 B 的价值为 b,字符串 C 的价值为 c
她拿到了一个长度为 n 的字符串,你需要在其中找到一些有价值的子串 (指字符串中连续的一段),并统计价值之和的最大值。
注:已被计算价值过的字符不能重复计算价值!如 "niconico" 要么当作 "nico" + "nico" 计 2a 分,要么当作 "niconi" + "co" 计 b 分(其中 "co" 不计分)。
示例1
输入:
19 1 2 5
niconiconiconiconi~
输出:
7
说明:
"niconi"co"niconiconi"~
故为2+5=7分
示例2
输入:
6 1 2 5
nocole
输出:
0
思路
开门见山了,这道题可以采用动态规划的方式来解决。
首先,状态转移方程是:
dp[i] = Math.max(dp[i], Math.max(dp[i-3]+a, dp[i-5]+b, dp[i-9]+c))
其实也不难理解,就是没到一个地方,就判断一下符合 a、b、c 那个,在取最大的就行,然后用 dp 数组记录一下,注意:dp 数组是递增或平行的。
AC 代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
String[] split = line.split(" ");
int n = Integer.parseInt(split[0]);
int a = Integer.parseInt(split[1]);
int b = Integer.parseInt(split[2]);
int c = Integer.parseInt(split[3]);
String line1 = sc.nextLine();
long res = run1(n, a, b, c, line1);
System.out.println(res);
}
public static long run1(int n, int a, int b, int c, String s) {
if (s == null || s.length() < 4) {
return 0;
}
long[] dp = new long[n];
for (int i = 3; i < n; i ++) {
dp[i] = dp[i - 1];
if (i >= 3 && s.substring(i- 3, i + 1).equals("nico")) {
dp[i] = Math.max(dp[i], dp[i - 3] + a);
}
if (i >=5 && s.substring(i - 5, i + 1).equals("niconi")) {
dp[i] = Math.max(dp[i], dp[i - 5] + b);
}
if (i >= 9 && s.substring(i - 9, i + 1).equals("niconiconi")) {
dp[i] = Math.max(dp[i], dp[i - 9] + c);
}
}
return dp[n - 1];
}
}
- 时间复杂度:O(N), N 为字符串长度,需要遍历一遍
- 空间复杂度:O(N), N 为字符串长度,需要创建 dp 数组