import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
int n=in.nextInt();
long []a=new long[n+1];
for(int i=1;i<=n;i++){
a[i]=in.nextLong();
}
long[][]dp=new long[n+1][n+1];
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
//从i位置到j,i到j-1然后+1
dp[i][j]=dp[i][j-1]+a[j];
}
}
//最后我们思考,他的区间一定是连续,并且不重叠的
for(int i=0;i<=n;i++) {
dp[0][i]=dp[i][0]=0x3f3f3f3f3f3f3f3fL;
}
long min=0x3f3f3f3f3f3f3f3fL;
//换句话,正确的话,就是暴力枚举,一个枚举左边的左端点,另一个枚举右端点,再来一个枚举右边的左端点,来一个枚举右边的右端点
//左端点从左侧,开始最后的n,但是细想一下,左端点是否可以等于n,答案应该是不可以的,左端点的右端点也不该到n,右端点的左端点肯定不可以和那个是左端点的右连起来
for(int i=1;i<n;i++){
for(int j=i;j<n;j++){
for(int t=j+1;t<=n;t++) {
for (int k = t; k <= n; k++) {
min = Math.min(Math.abs(dp[i][j ] - dp[t][k]), min);
}
}
}
}
System.out.println(min);
}
}
那么我们该如何优化呢?,
在这里引入数据结构
TheeSet:特点有序性,唯一性,插入删除查找都是O(logN)(内部是红黑)
first(返回数组中最小的元素)
last(返回数组中最大的元素)
higher(E e)返回集合中大于给定元素的最小元素
lower(E e):返回集合中严格小于给定元素的最大元素
ceiling(E e)返回集合中最小的大于或等于给定元素的元素
引入这个结构是为了让他有序,我们根据这个有序,随便来组合,不管他重复与否,全给他放入,
复制代码
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
long[] a = new long[n + 1];
for (int i = 1; i <= n; i++) {
a[i] = scanner.nextInt();
a[i] += a[i - 1];
}
TreeSet<Long> s = new TreeSet<>();
//初始化一个很大数字
long ans = 1000000000L;
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
//从1开始不断因为我们前缀和,所以需要不断减去a[i-1]的值,从a[1]-a[0],a[2]-a[0]...a[2]-a[1]...,不断求出不同位置的前缀和
if (!s.contains(a[j] - a[i - 1])) {
//假如s里面之前已经有了这个值,就说明两个数字相同,直接返回0就行
s.add(a[j] - a[i - 1]);
} else {
System.out.println(0);
return;
}
}
}
//此时已经把所有的数组都处理好了,然后我们需要做
for (int i = 1; i < n; i++) {
for (int j = 1; j <= i; j++) {
//t会走到所有的元素,假如TreeSet里面有(你要是说有最大的,最大的你想找较小的,
// 那么是否我们会找到较小的,然后找到最大的,所以不用去顾虑顺序啥的
long t = a[i] - a[j - 1];
// higher(E e)返回集合中大于给定元素的最小元素
//我在思考一个问题假如说 a b c x y z 假如说a+b和b+c他俩相差最小的情况呢,那么是否ac就可以,b不用管
//或者a b c 我们发现一个问题,假如出现重复的最小的情况,那么不需要重复的,换句话说 a+b 和b+c最小,其实不用看b,a和c最小
//我思考的是什么(如何保证两个前缀和,之间没有重复元素,假如有重复元素不就不可以了吗,但是实际上两个出现重复就不需要看重复
//这样一想,一切的2个连续子数组之和,求最小即可,有重复也可以(我重复的可以认为是把重复的去除)
Long p = s.higher(t);
if (p == null) {
//假如没有比他大的,那就去找first(返回数组中最小的元素)
//这里就是需要处理一下边界条件,但是假如是空,返回任意一个即可,无需说是一定就first
p = s.first();
}
//没有比他大的,然后用t这个值减去p这个值
ans = Math.min(ans, Math.abs(t - p));
}
}
System.out.println(ans);