「这是我参与11月更文挑战的第 1 天,活动详情查看:2021最后一次更文挑战」。
子数组最大连续和
给定一个长度为 的数组,数组中的数为整数。
请你选择一个非空连续子数组,使该子数组所有数之和尽可能大。求这个最大值。
输入描述:
第一行为一个正整数 ,代表数组的长度。 1≤n≤10^5
第二行为 个整数 ai,用空格隔开,代表数组中的每一个数。∣ai∣≤10^9
输出描述:
连续子数组的最大之和。
示例1
输入:
3
3 -4 5
输出:
5
分析
求子数组的最大值, 以 i 结尾的子数组最大值有两种可能
- 以 i - 1 结尾子数组的最大值 + i位置的数
- nums[i]
定义 dp 数组, dp[i] 表示 以 i 结尾子数组的最大值, 遍历 dp 数组,找到最大值 即为所求
dp[i] = ( i - 1 >= 0 && dp[i - 1] > 0) ? dp[i - 1] + nums[i] : nums[i];
AC 代码:
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int len = in.nextInt();
int[] arr = new int[len];
int index = 0;
while(index < len){
arr[index++] = in.nextInt();
}
long ans = getResult(arr);
System.out.println(ans);
}
}
static long getResult(int[] arr){
long dp = arr[0];
long ans = arr[0];
for(int i = 1 ; i < arr.length; i++){
dp = dp > 0 ? dp + arr[i] : arr[i];
ans = Math.max(ans, dp);
}
return ans;
}
}
不相邻取数
小红拿到了一个数组。她想取一些不相邻的数,使得取出来的数之和尽可能大。你能帮帮她吗?\
输入描述:
第一行输入一个正整数 ,代表数组长度
第二行输入 个正整数 ai ,代表整个数组。
1≤n≤10^5 , 1≤ai≤10^9
输出描述:
不相邻的数的最大和。
示例1
输入:
4
2 6 4 1
输出:
7
分析:
不相邻取数, 定义 dp 数组 dp[i] 表示 从以 i 结尾的子数组中不相邻取数获取的最大值
对于 dp[i], 如果 取 i 位置的数字 当前取出的数之和 为 dp[i-2] + nums[i], 如果不取 i 位置的数字 当前取出的数之和 为 dp[i-1]
dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i])
AC 代码
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int len = in.nextInt();
int[] nums = new int[len];
for(int i = 0 ; i < len;i++){
nums[i] = in.nextInt();
}
System.out.println(getResult(nums));
}
}
static long getResult(int[] nums){
long ans = nums[0];
long pre = nums[0];
long lastTwo = 0;
for (int i = 1; i < nums.length; i++) {
long rob = i - 2 >= 0 ? lastTwo + nums[i] : nums[i];
ans = Math.max(pre, rob);
lastTwo = pre;
pre = ans;
}
return ans;
}
}
nico和niconiconi
给定一个字符串 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分
分析:
定义 dp 数组, dp[i] 表示 以位置 i 结尾的字符串的最大价值
首先 : **dp[i] = dp[i - 1] **( i >= 0)
当 i 位置的字符为 ‘o’ 时, 并且 i - 3 >= 0 && s.substring(i - 3, i + 1).equals("nico") 时 : dp[i] = Math.max(dp[i], a + (i >= 4?dp[i - 4] : 0));
依次类推 当 i 位置的字符为‘i’时的
- i>=5 && str.substring(i-5,i+1).equals("niconi") : dp[i] = Math.max(dp[i], b + (i>=6?dp[i-6] : 0))
- i>=9 && str.substring(i-9,i+1).equals("niconiconi") : dp[i] = Math.max(dp[i], c + (i>=10?dp[i-10] : 0))
AC 代码:
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int len = in.nextInt();
int a = in.nextInt();
int b = in.nextInt();
int c = in.nextInt();
String str = in.next();
System.out.println(getScore(str, a, b, c));
}
}
static long getScore(String str, int a, int b, int c){
int len = str.length();
long[] dp = new long[len];
for(int i = 3; i< len;i++){
dp[i]= dp[i-1];
if(i>=3 && str.substring(i-3,i+1).equals("nico")){
dp[i] = Math.max(dp[i], a + (i>=4?dp[i-4] : 0));
}
if(i>=5 && str.substring(i-5,i+1).equals("niconi")){
dp[i] = Math.max(dp[i], b + (i>=6?dp[i-6] : 0));
}
if(i>=9 && str.substring(i-9,i+1).equals("niconiconi")){
dp[i] = Math.max(dp[i], c + (i>=10?dp[i-10] : 0));
}
}
return dp[len-1];
}
}
TIP
线性 DP 可以考虑使用有限的变量替代 DP 叔祖, 降低空间复杂度