记录阿里的在线面试题。
数组切片题
题设
对于一个长度为N的整型数组A,数组里所有的数都是正整数,对于两个满足0<=X<=Y<N
的整数,A[X], A[X+1]...A[Y]
构成A的一个切片,记作(X, Y)
。
用三个下标m1, m2, m3
下标满足条件0<m1, m2+1<m2, m2+1<m3<N-1
。
可以把这个整型数组分成(0, m1-1), (m1+1, m2-1), (m2+1, m3-1), (m3+1, N-1)
四个切片。如果这四个切片中的整数求和相等,称作“四等分”。
编写一个函数,求一个给定的整型数组是否可以四等分看,如果可以,返回一个布尔类型的true
,如果不可以返回一个布尔类型的false
。
限制条件:数组A最多有1,000,000项,数组中的整数取值范围介于-1,000,000到1,000,000之间。
要求:函数的计算复杂度为O(N)
,使用额外存储空间(除了输入的数组之外)最多为O(N)
。
例子:
对于数组A=[1, 5, 1, 1, 1, 1, 4, 1, 7, 3, 7]存在下标2, 7, 9使得数组分成四个分片[2, 5], [1, 1, 1, 4], [7], [7],这三个分片内整数之和相等,所以对于这个数组,函数应该返回true
。
对于数组A=[10, 2, 11, 13, 1, 1, 1, 1, 1],找不到能把数组四等分的下标,所以函数应该返回false
。
解题过程
很遗憾,当时把题目看错了,因为室友前一天做了,所以以为下表元素是算在求和之内的。直到最后五分钟才意识到,已经晚了。
第一种思路当然是暴力求解,三个for
循环,但是这显然是不行的。因为复杂度为O(N^3)
。
我这里采用的方法,受到了很多排序算法的启发,步骤如下:
- 使用三个游标,先初始化游标, 初始位置为1,3,5,计算四个子块的和。
- 然后进入
while
循环,判断子块和是否相等,如果相等返回true
结束。
- 找出最小和的游标,然后将游标右移一位。
- 注意,游标移动的时候,可能会影响到后面的游标,因此要做出判断是否移动后续游标,更新其它游标位置和各子块的和。
- 重复2,3,4步骤,直到第四块和成为了最小块或三号游标到达了倒数第二个位置(底部),返回
false
结束。
我把这个方法叫做“暴力逻辑求解”,暂时没想到其他方法……
程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| package cn.sjtunix.job;
import java.util.*;
public class sum3 {
static private int min(int[] a) { int N = a.length; int p = 0; for(int i=0; i<N; i++) { if(a[i] < a[p]) p = i; } return p; } static boolean resolve(int[] A) { int N = A.length; if(N < 7) return false; int p1 = 1; int p2 = 3; int p3 = 5; int[] sum = new int[4]; sum[0] = A[0]; sum[1] = A[2]; sum[2] = A[4]; sum[3] = 0; for(int i=6; i<N; i++) sum[3] += A[i]; while(p3<N-1) { if(sum[0]==sum[1] && sum[1]==sum[2] && sum[2]==sum[3]) return true; switch(min(sum)) { case 0 : sum[0] += A[p1]; sum[1] -= A[p1+1]; p1++; if(p1+1==p2) { sum[1] += A[p2]; sum[2] -= A[p2+1]; p2++; } if(p2+1==p3) { sum[2] += A[p3]; sum[3] -= A[p3+1]; p3++; } break; case 1 : sum[1] += A[p2]; sum[2] -= A[p2+1]; p2++; if(p2+1==p3) { sum[2] += A[p3]; sum[3] -= A[p3+1]; p3++; } break; case 2 : sum[2] += A[p3]; sum[3] -= A[p3+1]; p3++; break; case 3 : return false; } } return false; }
public static void main(String[] args){ ArrayList<Integer> inputs = new ArrayList<Integer>(); Scanner in = new Scanner(System.in); String line = in.nextLine(); while(line != null && !line.isEmpty()) { int value = Integer.parseInt(line.trim()); if(value == 0) break; inputs.add(value); line = in.nextLine(); } int[] A = new int[inputs.size()]; for(int i=0; i<inputs.size(); i++) { A[i] = inputs.get(i).intValue(); } Boolean res = resolve(A);
System.out.println(String.valueOf(res)); } }
|
程序复杂度满足O(N)
要求。