1.找出數組中重複的數字 ----《劍指Offer》題解(Java)

題目

給定一個長度爲 n 的整數數組 nums,數組中全部的數字都在 0∼n−1 的範圍內。java

數組中某些數字是重複的,但不知道有幾個數字重複了,也不知道每一個數字重複了幾回。算法

請找出數組中任意一個重複的數字。數組

注意:若是某些數字不在 0∼n−1 的範圍內,或數組中不包含重複數字,則返回 -1;code

樣例
給定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。io

返回 2 或 3。class

算法思路

找重複數字能夠直接用HashMap來解決,但須要額外的空間。
本題能夠只用O(1)的空間複雜度來實現,具體思路是:
因爲數字範圍是[0, n-1],數組長度是n,所以可把數組當作是數字的槽位,依次將數字放到對應數組下標的位置去。
遍歷數組,將當前元素nums[i]放到它對應的數組下標的位置去,即swap(nums[i] , nums[nums[i]]),注意交換到位置i的數字也要繼續放到它相應的槽去,依次循環直到當前位置i放入了正確的數字,即nums[i] == i。
假如在將當前位置的元素放到正確位置的時候,發現該位置已是正確的數字了,說明有重複,直接返回該數字便可。
須要注意,題目中「若是某些數字不在 0∼n−1 的範圍內,則返回 -1」,這是個坑,須要提早判斷,若是在遍歷數組中判斷則可能先找到重複元素,就退出,超出範圍的數還沒被判斷到。
算法的時間複雜度是O(n)循環

代碼實現

class Solution {
    public int duplicateInArray(int[] nums) {
        if (nums == null || nums.length == 0) return -1;
        int n = nums.length;
        //提早遍歷判斷"若是某些數字不在 0∼n−1 的範圍內,則返回 -1"
        for (int i=0; i<n; i++) { 
            if (!(nums[i] >= 0 && nums[i] < n)) return -1;
        }
        
        for (int i=0; i<n; i++) {
            //循環將當前位置的元素放到對應的槽去
            while (nums[i] != nums[nums[i]]) swap(nums, i, nums[i]); 
            
            //當前元素應該放到對應位置,但該位置的數字跟當前的同樣,即重複了
            if (nums[i] != i && nums[i] == nums[nums[i]]) return nums[i]; 
        }
        
        return -1;
    }
    
    //交換數組兩個元素
    private void swap(int[] nums, int i, int j) {
        nums[i] = nums[i] ^ nums[j];
        nums[j] = nums[i] ^ nums[j];
        nums[i] = nums[i] ^ nums[j];
    }
}
相關文章
相關標籤/搜索