2月2日 剑指offer第二次刷题

剑指 Offer 03. 数组中重复的数字

1.这是先对数组排序然后遍历数组找出重复数(还记得当时做的时候巨搞笑,if里面总是写不对,现在为自己的愚蠢反思。)时间是O(nlogn)

lass Solution {
    public int findRepeatNumber(int[] nums) {
        Arrays.sort(nums);
        for(int i=0;i<nums.length;i++){
        if(nums[i]-nums[i+1]==0)
        {
            return nums[i];
        }
        }
        return 0;
        }

    }

2.可以使用哈希表来解决,如果哈希表中没有这个数字,就加入到哈希表中,如果有,就返回这个重复数字。时间O(n),但是空间也增大了O(n)。

class Solution {
    public int findRepeatNumber(int[] nums) {
        Set<Integer> set = new HashSet<>();
        int repeat = -1;
        for (int num : nums) {
            if (!set.add(num)) {
                repeat = num;
                break;
            }
        }
    return repeat;
    }
}

上面是学习的set的写法,学到了set.add(),当新元素添加返回T,否则返回F。下面是我自己之前写的,只能说,高低一眼就看出来了(~.~).

class Solution {
    public int findRepeatNumber(int[] nums) {
        Map<Integer, Integer> chongfu = new HashMap();
        for(int i=0;i<nums.length;i++){
            if(chongfu.get(nums[i])==null){
                chongfu.put(nums[i],1);
            }
            else{
                return nums[i];
            }
                

        }
        return -1;
    }
}

3.如果让空间变成O(1)就好了,所以又学到了一个原地交换的方法,真的感觉很奇妙,确实让我想,我夜想不出来啊。

遍历数组 nums ,设索引初始值为 i=0 :

若 nums[i]=i : 说明此数字已在对应索引位置,无需交换,因此跳过;

若 nums[nums[i]]=nums[i] : 代表索引 nums[i] 处和索引 i 处的元素值都为 nums[i] ,即找到一组重复值,返回此值 nums[i] ;

否则: 交换索引为 nums[i] 的元素值,将此数字交换至对应索引位置。

如果没有返回结果,则返回-1。

class Solution {
    public int findRepeatNumber(int[] nums) {
        int i = 0;
        while(i < nums.length) {
            if(nums[i] == i) {
                i++;
                continue;
            }
            if(nums[nums[i]] == nums[i]) return nums[i];
            int t = nums[i];
            nums[i] = nums[t];
            nums[t] = t;
        }
        return -1;
    }
}

只能说让我去理解,我也是理解了好半天,然后过一会还会忘掉,这方法着实很牛,也让我头大。(重点重点重点!!!)

当然,这题肯定少不了拓展,比如找出全部重复数啥的,下面是另一个拓展题。

不修改数组找重复数

题目要求和上面一样,就是不能修改数组(好头大啊)

看了下别人的思路,使用类似二分查找的方法,看完只能大声称赞:妙哉!

把数组从中间分成两段,1—m和m+1—n,看数组中1—m的个数有多少,如果超过m个,就说明前半段一定有重复的,否则就是后半段,然后继续二分二分,直到找到重复数字。(又要码代码了,痛啊),这个方法感觉抄了一遍还是不太理解,对一些东西还是迷迷糊糊的,还是要多看多记多码。

class T3t{
    public int getDuplicate(int[] arr,int length){
        if (arr == null || length <= 0) {
            return -1;
        }

        int start = 1;
        int end = arr.length - 1;
        while (start <= end) {
            int middle = start + (end - start) / 2;
            int count = countRangeNumbers(arr, start, middle);
            if (start == middle) {
                if (count > 1) {
                    return start;
                } else {
                    break;
                }
            }
            if (count > (middle - start + 1)) {
                end = middle - 1;
            } else {
                start = middle + 1;
            }
        }
        return -1;
    }

    public int countRangeNumbers(int[] arr, int start, int end) {
        int count = 0;
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] >= start && arr[i] <= end) {
                count ++;
            }
        }
        return count;
    }
}

最后的最后,时间O(nlogn),空间O(1),时间换空间,当然也有弊端,这个方法找不了所有的重复数,比如在1—2,如果出现两个2,这个方法却找不到是各一个还是两个一或者两个二。

数组这一节,以这两个题收尾,过程还是有些绕弯了,但是也有所收获,下一节,字符串咯。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值