前缀和(preSum)是一种常用的、较为高效的预处理方式,相比于暴力解法,能够有效减低查询的时间复杂度。
题目
有n个战士站成一排,分别编号为1、2、3、...、n,战士的战斗力等于他的编号,有一些战士只会进攻,有一些战士只会防守。
现在我们要将他们从某个点开始分成两个阵营,假设这个点为pos(0<=pos<=n),则编号为1、2、3、...、pos的战士为第一个阵营, pos+1、pos+2、...、n的战士为第二个阵营。假设pos为0时, 说明第一阵营没有战士,所有战土都在第二阵营。
我们令第一个阵营为进攻方,第二个阵营为防守方,假设第一个阵营中能够进攻的战士战斗力总和为w,第二个阵营中能够防守的战士战斗力总和为v,我们希望|w-v|的值最小,其中||为绝对值符号,求|w-v|最小值。
输入
第一行输入一个正整数n,表示战士的数量(1<=n)。
第二行给出一个字符串s,仅由字符0或1组成,字符串中的每一位分别代表每一位的战士属性,0代表这个战士只会进攻,1代表这个战士只会防守。
输出
输出一行一个整数表示|w-v|最小值。
示例
输入
4
0011
输出
1
思路
前缀和
使用一个数组L[n],来统计左边的攻击力,另一个数组R[n],来统计右边的防御力。
然后在一个循环中找出|w-v|最小值。
代码
public class TestDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
if(n==1){
System.out.println(0);
}
String s = sc.next();
int[] L = new int[n];
int[] R = new int[n];
int countL = 0;
int countR = 0;
for(int i=0;i<n;++i){
if(s.charAt(i)=='0'){
countL+=i+1;
}
L[i] = countL;
}
for(int i=n-1;i>0;--i){
if(s.charAt(i)=='1'){
countR+=i+1;
}
R[i] = countR;
}
int min = Integer.MAX_VALUE;
for(int i=0;i<n-1;++i){
int fight =Math.abs(L[i]-R[i+1]);
min=Math.min(min,fight);
}
min=Math.min(min,Math.min(R[n-1],L[n-1]));
System.out.println(min);
}
}