1、最长公共序列
dp[i][j]:表示字符串1与字符串2在索引为i与j时,最长的公共序列。
初始化:无
循环:双层循环一层字符串1的长度,一层字符串2的长度;
转移:
-若两个索引恰好相同:dp[i][j] = dp[i - 1][j - 1]
-若两个索引不相同:dp[i][j] = Math.max(dp[i][j - 1],dp[i - 1][j])
代码:
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int len1 = scanner.nextInt();
int len2 = scanner.nextInt();
String str1 = scanner.next();
String str2 = scanner.next();
int[][] dp = new int[len1 + 1][len2 + 1];
for(int i = 1; i <= len1; i++){
char c1 = str1.charAt(i - 1);
for(int j = 1; j <= len2; j++){
char c2 = str2.charAt(j - 1);
if(c1 == c2){
dp[i][j] = dp[i - 1][j - 1] + 1;
}else{
dp[i][j] = Math.max(dp[i - 1][j],dp[i][j - 1]);
}
}
}
System.out.println(dp[len1][len2]);
}
}
2、乘积为正的最长连续子数组
dp[i][0]:表示前i个数为正数的最长长度
dp[i][1]:表示前i个数为负数的最长长度
初始化:因为dp第零个数为正或是负长度都为0
循环:双层循环一层字符串1的长度,一层字符串2的长度;
转移:
-若当前元素为正:
- dp[i][0]的转移:前i - 1个数为正的最大长度加一 dp[i][0] = dp[i - 1][0] + 1;
- dp[i][1]的转移:前i - 1个数为负的数量如果不为0,说明前面有负数,此时这个数为正数,那么相乘后,负数的长度有加1,所以要先if判断dp[i - 1][1] ? 0,不为0就对dp[i][1] = dp[i - 1][1] + 1
-若当前元素为负数:
- dp[i][1]的转移:前i - 1个数为正的最大长度加一 dp[i][1] = dp[i - 1][0] + 1;道理相同,成绩得为负
- dp[i][0]的转移:前i - 1个数为负的数量不为0,说明前面有负数,此时这个数为负数,那么相乘后,正数长度加1,dp[i][0] = dp[i - 1][1] + 1;
代码:
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int size = scanner.nextInt();
int[] nums = new int[size];
for(int i = 0; i < size; i++){
nums[i] = scanner.nextInt();
}
int[][] dp = new int[size + 1][2];
int res = 0;
for(int i = 1; i <= size; i++){
int val = nums[i - 1];
if(val > 0){
dp[i][0] = dp[i - 1][0] + 1;
if(dp[i - 1][1] != 0){
dp[i][1] = dp[i - 1][1] + 1;
}
}else if(val < 0){
dp[i][1] = dp[i - 1][0] + 1;
if(dp[i - 1][1] != 0){
dp[i][0] = dp[i - 1][1] + 1;
}
}
res = Math.max(res,dp[i][0]);
}
System.out.println(res);
}
}
3、环形数组的连续子数组最大和
题目:
描述
给定一个长度为 nn 的环形整数数组,请你求出该数组的 非空 连续子数组 的最大可能和 。
环形数组 意味着数组的末端将会与开头相连呈环状。例如,对于数组 [1,3,-5,2,-4][1,3,−5,2,−4]而言,第一个数 11的前一个数是最后一个数 -4−4。
输入:
3
5 -3 5
输出:
10
说明:从子数组 [5,5] 得到最大和 5 + 5 = 10
分析
结果分为两种情况:
1、最大的和在中间,没有两端分开
2、最大的和在左右两端,中间是最小值(二者相加等于数组总和)
表示:
premax:表示上一项的最大和值;max:表示最大的和值
premin:表示上一项的最小和值;min:表示最小和值
若最后的max>0,则可能存在两端最大的情况使用Math.max(sum-min,max)作比较;
若最后的max<0,则表示大家都是负的,直接用max就行
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int size = sc.nextInt();
int[] nums = new int[size];
for(int i = 0; i < size; i++){
nums[i] = sc.nextInt();
}
int sum = nums[0]; int premax = nums[0]; int max = nums[0];
int premin = nums[0]; int min = nums[0];
for(int i = 1; i < size; i++){
sum += nums[i];
premax = Math.max(premax,0) + nums[i];
max = Math.max(max,premax);
premin = Math.min(premin,0) + nums[i];
min = Math.min(min,premin);
}
int res = max > 0 ? Math.max(max,sum - min) : max;
System.out.println(res);
}
}