个人博客
www.tothefor.com
蓝桥杯复习知识点汇总
目录
分为连续子数组和非连续子数组,在一维的情况下可以等同于字串和子序列的最大和。
连续子数组
对于一个数A[ i ],若是A[ i ] 的左边累计数非负,那么加上A[ i ] 能使得值不小于A[ i ],认为累计值对整体和是有贡献的。如果前几项累计值负数,则认为有害于总和。
一维
动态规划:算法时间复杂度:O(n)
对于一个数A[ i ],若是A[ i ] 的左边累计数非负,那么加上A[ i ] 能使得值不小于A[ i ],认为累计值对整体和是有贡献的。如果前几项累计值负数,则认为有害于总和,应丢弃。
dp[ i ]表示以a[ i ]结尾的「连续子数组的最大和」,不是整个数组的最大子数组和。
即:dp[ i ] = max{dp[ i-1 ] + a[ i ],a[ i ] };
初始状态:dp[0] = a[0];
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @Author DragonOne
* @Date 2021/12/5 21:27
* @墨水记忆 www.tothefor.com
*/
public class Main {
public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
public static Scanner sc = new Scanner(System.in);
public static int maxd = 200000+7;
public static int INF = 0x3f3f3f3f;
public static int mod = 998244353;
public static void main(String[] args) throws Exception {
int n = nextInt();
int[] a = new int[maxd];
int[] dp = new int[maxd]; //dp[i]表示以a[i]结尾的「连续子数组的最大和」
for(int i=1;i<=n;++i) a[i] = nextInt();
int ans = a[1]; //ans用来存储最后的答案
dp[1]=a[1]; //初始化第一个数默认是它自己
for(int i=1;i<=n;++i){ //如果a数组是从0开始存的,这里必须从第二个数开始,否则会存在下标为 0-1=-1 的情况.而现在这里从1或2开始都行
dp[i]=Math.max(dp[i-1]+a[i],a[i]);
ans=Math.max(ans,dp[i]);
}
System.out.println(ans);
closeAll();
}
public static void cinInit(){
cin.wordChars('a', 'z');
cin.wordChars('A', 'Z');
cin.wordChars(128 + 32, 255);
cin.whitespaceChars(0, ' ');
cin.commentChar('/');
cin.quoteChar('"');
cin.quoteChar('\'');
cin.parseNumbers();
}
public static int nextInt() throws Exception {
cin.nextToken();
return (int) cin.nval;
}
public static long nextLong() throws Exception {
cin.nextToken();
return (long) cin.nval;
}
public static double nextDouble() throws Exception {
cin.nextToken();
return cin.nval;
}
public static String nextString() throws Exception {
cin.nextToken();
return cin.sval;
}
public static void closeAll() throws Exception {
cout.close();
in.close();
out.close();
}
}
测试数据:
//输入
9
-2 1 -3 4 -1 2 1 -5 4
//输出
6
滚动数组(空间优化)
因为,dp[ i ] 只与dp[ i-1] 有关,所以可以用一个变量 midsum 来维护对于当前 dp[ i ]的dp[ i-1 ] 的值是多少,从而让空间复杂度降低到 O(1),这类似「滚动数组」的思想。
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @Author DragonOne
* @Date 2021/12/5 21:27
* @墨水记忆 www.tothefor.com
*/
public class Main {
public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
public static Scanner sc = new Scanner(System.in);
public static int maxd = 200000+7;
public static int INF = 0x3f3f3f3f;
public static int mod = 998244353;
public static void main(String[] args) throws Exception {
int n = nextInt();
int[] a = new int[100]; //原数组
for(int i=1;i<=n;++i) a[i] = nextInt();
int midsum = a[1]; //初始化
int ans = a[1]; //默认答案为第一个数
for(int i=1;i<=n;++i){
midsum=Math.max(midsum+a[i],a[i]);
ans=Math.max(ans,midsum);
}
System.out.println(ans);
closeAll();
}
public static void cinInit(){
cin.wordChars('a', 'z');
cin.wordChars('A', 'Z');
cin.wordChars(128 + 32, 255);
cin.whitespaceChars(0, ' ');
cin.commentChar('/');
cin.quoteChar('"');
cin.quoteChar('\'');
cin.parseNumbers();
}
public static int nextInt() throws Exception {
cin.nextToken();
return (int) cin.nval;
}
public static long nextLong() throws Exception {
cin.nextToken();
return (long) cin.nval;
}
public static double nextDouble() throws Exception {
cin.nextToken();
return cin.nval;
}
public static String nextString() throws Exception {
cin.nextToken();
return cin.sval;
}
public static void closeAll() throws Exception {
cout.close();
in.close();
out.close();
}
}
二维
将二维转化为一维数组计算,然后计算一维的最大子数组问题。
方法:将每一列求一个前缀和,得到一个一维数组。
时间复杂度:O(n*n*m)
矩阵转置
看网上的一些说明,当行大于列时进行转置(因为遍历的时候是遍历的行,所以找行、列中的较小值作为行可以减少遍历次数),但感觉根本没用,因为后面求的时候行和列都用到了,时间复杂度根本没变。但是这里也写上吧。
public static int[][] Matreverse(int[][] a,int m,int n) { //m行n列的数组a,a数组下标从1开始
int[][] newArr = new int[n+5][m+5]; //转化后的n行m列数组
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
newArr[j][i] = a[i][j];
}
}
return newArr;
}
代码实现
这里没有用转置。(感觉用了没用)
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @Author DragonOne
* @Date 2021/12/5 21:27
* @墨水记忆 www.tothefor.com
*/
public class Main {
public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
public static Scanner sc = new Scanner(System.in);
public static int maxd = 200000+7;
public static int INF = 0x3f3f3f3f;
public static int mod = 998244353;
//求一维数组的最大子数组
public static int getOne(int[]a,int n){ //n为长度,a数组是下标从1开始存储的
int[] dp = new int[maxd]; //dp[i]表示以a[i]结尾的「连续子数组的最大和」
int ans = a[1]; //ans用来存储最后的答案
dp[1]=a[1]; //初始化第一个数默认是它自己
for(int i=1;i<=n;++i){ //如果a数组是从0开始存的,这里必须从第二个数开始,否则会存在下标为 0-1=-1 的情况.而现在这里从1或2开始都行
dp[i]=Math.max(dp[i-1]+a[i],a[i]);
ans=Math.max(ans,dp[i]);
}
return ans;
}
public static void main(String[] args) throws Exception {
int n = nextInt(); //行
int m = nextInt(); //列
int[][] a = new int[100][100]; //原数组
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
a[i][j] = nextInt();
}
}
//求每一列的前缀和,每一列中从第一行到第i行的和
int[][] p = new int[105][105]; //p[i][j]表示j这一列的前i个数的和
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
p[i][j]=p[i-1][j]+a[i][j];
}
}
int maxans = 0;
for(int i=1;i<=n;++i){ //第i行
for(int j=i;j<=n;++j){ //到最后一行
maxans=Math.max(maxans,getOne(p[i],m));
}
}
System.out.println(maxans);
closeAll();
}
public static void cinInit(){
cin.wordChars('a', 'z');
cin.wordChars('A', 'Z');
cin.wordChars(128 + 32, 255);
cin.whitespaceChars(0, ' ');
cin.commentChar('/');
cin.quoteChar('"');
cin.quoteChar('\'');
cin.parseNumbers();
}
public static int nextInt() throws Exception {
cin.nextToken();
return (int) cin.nval;
}
public static long nextLong() throws Exception {
cin.nextToken();
return (long) cin.nval;
}
public static double nextDouble() throws Exception {
cin.nextToken();
return cin.nval;
}
public static String nextString() throws Exception {
cin.nextToken();
return cin.sval;
}
public static void closeAll() throws Exception {
cout.close();
in.close();
out.close();
}
}
测试数据:
//输入
2 3
1 2 3
3 -1 4
//输出
12