考试后对这个题目很感兴趣所以花时间再做了一遍,相信阿里的在线编程题都是随机的.如果各位以后做刚好遇到这个题目..纯属巧合 : )
对于一个长度为N的整形数组A,数组里所有的数都是正数,用三个下标m1,m2,m3
(满足条件 0
设数组首尾两端指针low
和high
, 切片1-4的和为sum1~sum4
, low
和 high
往中间靠拢, 如果有解, 必定在high>low
的情况下出现sum1 == sum4
; 那么此时我们记录下来即将去掉的断点i =low+1
和j = low-1
; 然后我们同样的方法来得到sum3 == sum4
,如果刚好, 有可能 low+1 = high-1
; 那么判断sum1==sum2
就知道是否有解了. 那要没这么刚好,(我们设当前数组的状态为Status
). 我们来做一个指针的平移, 将i
往low
的方向平移,然后sum1 += A[i], sum2-=A[++i]
, 如果sum1 < sum2
, 继续平移i指针, 如果sum1 > sum2 ,sum2+= A[low++], 直到sum1 == sum2 ;
同样的方法我们将指针j
往high
的方向平移,处理sum3和sum4,
直到sum3 == sum4
; 这样,我们又回到了Status
这种情况,如果low
sum1 == sum4
就知道结果啦.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
/**
* @author Jiangjiaze
* @version Id: AliExam .java, v 0.1 2017/3/7 22:34 FancyKong
*/
public class AliExam {
static boolean resolve(int[] A) {
int low = 0;
int high = A.length - 1;
long sum1 = A[low];
long sum4 = A[high];
while (low != high)
//从中间向两边靠拢
if (sum1 == sum4) {
break;
} else if (sum1 < sum4) {
sum1 += A[++low];
} else {
sum4 += A[--high];
}
int i = low + 1; // 保存被切掉的元素的索引
int j = high - 1;
low += 2; // 跳过被切掉的元素
high -= 2;
if (low >= high) return false;
//同理,从中间向两边靠拢
long sum2 = A[low];
long sum3 = A[high];
while (low != high) {
if (sum2 == sum3) {
break;
} else if (sum2 < sum3) {
sum2 += A[++low];
} else {
sum3 += A[--high];
}
}
low++;
high--;
//如果high还是大于 low , 题目有无解还不知道
while (high > low) {
while (high >= low) {
//平移指针,sum1+ 而 sum2 -; 比较大小来移动low指针和i指针
sum1 += A[i];
sum2 -= A[++i];
while (sum1 > sum2) {
sum2 += A[low++];
}
if (sum1 == sum2) break;
}
while (high >= low) {
//同理
sum4 += A[j];
sum3 -= A[--j];
while (sum4 > sum3) {
sum3 += A[high--];
}
if (sum3 == sum4){
//不能像上面那样直接break,因为不知道sum1和sum4的大小
//加多一层判断,如果sum1小于sum4 break ; 大于的话sum4需要继续加
if(sum1 == sum4 && low == high) return true;
if(sum1 < sum4)
break;
}
}
}
return low == high && sum1 == sum2 && sum1 == sum3;
}
public static void main(String[] args) {
//考试上面的main函数不是我这样的.
//单纯为了测试一下而已
mainTest(null);
}
public static void mainTest(String[] args) {
ArrayList inputs = new ArrayList();
Scanner in = new Scanner(System.in);
int n = in.nextInt(); //每小段多少个元素,总共4小段
int random[] = new int[n];
//生成随机数的一小段
for (int i = 0; i < n; i++) {
random[i] = (int)(100*Math.random());
}
int[] A = new int[4*n+3];
System.arraycopy(random,0,A,0,n);
System.arraycopy(random,0,A,n+1,n);
System.arraycopy(random,0,A,2*n+2,n);
System.arraycopy(random,0,A,3*n+3,n);
//下面注释掉的只是做点交换,破除原来数组的中心对称
/*int div = A[n+1];
A[2] -= div;
A[n+3] +=div;
A[n+1] = A[n];
A[n] = div;*/
System.out.println(Arrays.toString(A));
Boolean res = resolve(A);
System.out.println(String.valueOf(res));
}
}
答案正确吗?
本人小白, 这样的解法算作是O(n)时间复杂度吗?
有疑问可以在回复和我交流.
阿里的实习生招聘系统超多BUG…