数组切分

题目描述

输入为一个int类型的数组,在数组中选择三个切割点,将该数组分为四个子数组(不包含切割点),若这四个子数组的和相等,则返回true, 否则返回false.
如:输入arr = [6,4,8,5,5,5,2,8,9,10]
输出:true。切分位置分别是2,5,8,形成的子数组是:[6,4,]、[5,5]、[2,8]、[10]

解题思路

使用两个指针l, r,l 指向数组头,r指向数组尾部,维护leftSum = sum[0]+..sum[l-1], rightSum = sum[r+1] + ... sum[arr.length-1]。若leftSum < rightSum , 则 l++, 更新leftSum; 若leftSum > rightSum, 则r--, 更新rightSum. 一直重复此步骤,直到leftSum = rightSum或l >= r - 3停止,若l >= r - 3,则返回false, 若leftSum = rightSum, 说明暂时找到了第一和第三个切割点,现在要在l, r之间找第二个切割点,这时我们可以利用HashSet在O(1)的时间复杂度内判断能否找到第二个合法的切割点。方法如下:HashSet里放(leftSum_rightSum). 其中leftSum代表数组arr从第0个位置到第i个位置(不包含i位置)的元素之和,rightSum代表数组arr从第i个位置到最后位置(不包含i位置)的元素之和。这样我们可以在leftSum = rigthSum的基础下, 用String lkey = String.valueOf(lsum * 2 + arr[l]);String rkey = String.valueOf(rsum * 2 + arr[r]);set.contains(lkey + "_" + rkey)判断是否存在第三个切分点,存在则返回true, 否则,寻找失败,继续下一次的寻找。

代码

public static boolean canSplits1(int[] arr) {
		if (arr == null || arr.length < 7) {
			return false;
		}
		HashSet set = new HashSet();
		int allSum = 0;//所有数的和
		for (int i = 0; i < arr.length; i++) {
			allSum += arr[i];
		}
		int leftSum = arr[0];//不包括当前位置的左部份累加和
		for (int i = 1; i < arr.length - 1; i++) {
			set.add(String.valueOf(leftSum) + "_" + String.valueOf(allSum - leftSum - arr[i]));
			leftSum += arr[i];
		}
		int l = 1;//左指针(第一个划分点)
		int lsum = arr[0];//第一部分的和
		int r = arr.length - 2;//右指针(第二个划分点)
		int rsum = arr[arr.length - 1];//最后一部分的和
		while (l < r - 3) {//中间剩余的数的个数必须大于3个
			if (lsum == rsum) {//找到了第一部分的和等于最后一部分的和的位置
				String lkey = String.valueOf(lsum * 2 + arr[l]);
				String rkey = String.valueOf(rsum * 2 + arr[r]);
				if (set.contains(lkey + "_" + rkey)) {
					return true;//可以划分
				}
				lsum += arr[l++];//或者写成 rsum += arr[r--];
			} else if (lsum < rsum) {
				lsum += arr[l++];
			} else {
				rsum += arr[r--];
			}
		}
		return false;
	}




你可能感兴趣的:(算法,数组切分,双指针)