AcWing 14. 不修改数组找出重复的数字(分治法)

如果不将思考题考虑在内的话,那么AcWing 13.找出数组中重复的数字中的方法1的代码是可以完全移植过来的。这里不再赘述。不过,由于这道题的样例里面不存在含有超出范围的数据以及全部数据均出现一次的情况,因此代码还可以进一步简化。

简化后的具体代码如下:

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        int n=nums.size();
        vector<int> v(n, 0);
        //统计出现次数
        for(auto &e: nums){
            v[e]++;
        }
        //遍历统计结果,发现有满足条件的则返回
        for(int i = 0; i < n; i++){
            if(v[i] > 1) return i;
        }
        return 0;
    }
};

现在,我们来解决思考题。由于要求空间复杂度为O(1),因此不可以再开辟等量空间统计出现次数。

为了解决问题,我们先按照元素所在的区间划分为等长的子区间(注意,这里的区间并不是数组的区间,而是数组中元素取值范围的区间)。然后再遍历数组统计落在这两个子区间里面元素的个数。假设所有的元素均是互异的,那么落在两个子区间里面元素的个数应该恰好等于区间长度。当存在重复元素时,两个子区间中应至少有一个是统计个数大于区间长度的。此时,只要在出现这种情况的子区间中继续如上的操作,最终就能得到重复的元素。该算法原理类似二分查找,不过要注意二分查找的子区间是按照数组划分的。

具体代码如下:

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        int lo = 1, hi = nums.size() - 1;
        while(lo <= hi){
            int sum = 0; //统计数组元素在左子区间范围中元素个数
            int mid = lo + (hi - lo) / 2; //将区间划分为[lo, mid]和[mid + 1, hi]
            for(auto e: nums){
                if(lo <= e && e <= mid) sum++;
            }
            if(sum <= (mid - lo + 1)) lo = mid + 1;
            else hi = mid - 1;
        }
        return lo;
    }
};

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值