給定一個長度爲 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]; } }