阿里巴巴集团2017暑期实习Java研发工程师在线编程题-数组分片

题目:一个整型(非负)数组,将其划分为总和相同的4个切片,例如:{2,5,1,1,1,1,4,1,7,3,7},切片操作后划分为:{2,5},{1,1,1,4},{7},{7},也就找到所谓的四等分点,切分点分别是1,1,3,切分点不算在总和内。输出能否分片。要求时间复杂度和空间复杂度为o(n)。

思路:
  1. 两个Map,一个存<总和,位置>,一个存<位置,总和>。
  2. 由于数组非负,先由头尾指针向中间逼近,先将数组分成三段< L,M,R >,如果左边大则左移尾指针,如果右边大则右移头指针,最后使得左右部分相等,大小记为A
  3. 然后处理中间部分M,看其能否分成两部分< LM,LR >,使得他们的总和都等于A。方法是从<总和,位置>的Map中找总和为2A的位置i,即满足LM==L,如果这个位置i存在并且在左右指针之间,根据尾指针和i以及Map<位置,总和>算出LR的和,判断是否等于A,如果相等,则输出true

{2,5,1,1,1,1,4,1,7,3,7}
       ↑            ↑    ↑
   头指针        i  尾指针

以下代码通过了在线编程的所有测试用例:
public class FourPiece {
    public static void main(String[] args){

//        int[] nums = {2,5,4,7,2,5,4,7,2,5,4,7,2,5,4,7,2,5,4,7,2,5,4,7};
//        int[] nums = {1,2,1,3,1,4,2};
        int[] nums = {2,5,1,1,1,1,4,1,7,3,7};
//        int[] nums = {10,2,11,13,1,1,5,1,1,1,10,2,11,12,5,1,1,1,1,1,10,2,11,10,5,1,1,1,1,34};
        System.out.print(canDevide(nums));
    }
    public static boolean canDevide(int[] nums){
        if(nums == null || nums.length < 7){
            return false;
        }
        HashMap<Long,Integer> indexMap = new HashMap<Long,Integer>();//<总和,位置>
        HashMap<Integer,Long> sumMap = new HashMap<Integer,Long>();//<位置,总和>

        long curSum = 0;
        for(int i = 0; i < nums.length; i++){
            indexMap.put(curSum,i);
            sumMap.put(i,curSum);
            curSum += nums[i];
        }
        long leftSum = nums[0];//最左段总和
        long rightSum = nums[nums.length - 1];//最右段总和
        int leftIndex = 1;//左分割点
        int rightIndex = nums.length - 2;//右分割点

        while(leftIndex + 3 < rightIndex){
            if(leftSum == rightSum){
                if(indexMap.get((leftSum << 1) + nums[leftIndex]) != null){
                    int middleIndex = indexMap.get((leftSum << 1) + nums[leftIndex]);//中间分割点
                    if(middleIndex > leftIndex + 1 && middleIndex < rightIndex - 1){
                        if(sumMap.get(rightIndex) - sumMap.get(middleIndex + 1) == leftSum){
                            return true;
                        }
                    }
                }
                leftSum += nums[leftIndex++];
                rightSum += nums[rightIndex--];
            }
            else{
                if(leftSum < rightSum){
                    leftSum += nums[leftIndex++];
                }
                else{
                    rightSum += nums[rightIndex--];
                }
            }
        }
        return false;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值