面试题(四)不修改数组找出重复的数字

题目:
不修改数组找出重复的数字。在一个长度为n+1的数组中的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。在不修改输入数组的情况下找出数组中任意一个重复数字。例如输入长度为8的数组{2, 3, 5, 4, 3, 2, 6, 7},则对应输出的是2或者3。

思路:(类似于2分查找)
对于一个整数范围i1~i2,如果在这个范围内的整数的数量超过i2-i1+1,那么此范围内的整数中必然有整数会出现多次。因此选定范围1~n/2,并记录输入数组中在此范围内的元素的数量,若数量大于n/2,则在此整数范围内必然有整数在数组中出现了多次,否则在范围(n/2)+1~n内必然有整数在数组中出现多次。对确定出现重复整数的范围再进行前面的划分和计数操作,直到找到重复的数字。

代码(含测试用例)

public static void main(String[] args){

        Q4 q4 = new Q4();
        q4.test1();
        q4.test2();
        q4.test3();
        q4.test4();

    }

    public int duplicate(int[] numbers, int length){

        // robust
        if(numbers == null || length <= 0)
            return -1;
        for(int i = 0; i < length; i++)
            if(numbers[i] < 1 || numbers[i] > length-1)
                return -1;

        int lo = 1;
        int hi = length-1;
        while(lo <= hi){
            int mid = (lo + hi)/2;
            //int mid = ((hi - lo) >> 1) + lo;
            int count = 0;

            //对范围内的元素个数进行计数
            for(int i = 0; i < length; i++)
            {
                if(numbers[i] <= mid && numbers[i] >= lo)
                    count++;
            }

            if(lo == hi)
            {
                if(count > 1)
                    return lo;
                else 
                    break;
            }

            // 根据检测情况调整会出现重复的整数范围
            if(count > mid - lo + 1)
                hi = mid;
            else
                lo = mid + 1;

        }

        return -1;

    }

    // no duplicate
    public void test1(){

        int[] nums = {1, 2, 3, 4, 5, 6};
        System.out.println(duplicate(nums, nums.length));
    }

    // has one duplicate
    public void test2(){

        int[] nums = {1, 2, 4, 5, 6, 3, 1};
        System.out.println(duplicate(nums, nums.length));
    }

    // multiple duplicates
    public void test3(){

        int[] nums = {1, 1, 3,4,5,3,2, 7};
        System.out.println(duplicate(nums, nums.length));
    }

    // null array
    public void test4(){

        System.out.println(duplicate(null, 0));
    }

性能:代码中含有两重循环,外层循环为二分查找,故时间复杂度为O(lgn),内循环时间复杂度为O(n),故总的时间复杂度为O(nlgn)。空间复杂度为O(1)。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值