算是一道簡單題,但是需要大家考慮時間和空間的複雜度,以及是否能修改原數組等情況。框裏圈出來的是解題的關鍵喲。
法一:暴力
很容易想,也很暴力!
雙層循環嵌套找到相同的數,時間複雜度達到O(n),空間複雜度O(1)
public int findRepeatNumber(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
for (int i= 0; i < n; i++) {
for (int j = i+1; j < n; j ++) {
if (nums[i] == nums[j]) {
return nums[i];
}
}
}
return -1;
}
法二 :額外定義數組
很容易想到用空間換時間的方法,於是定義一個數組。由於題目明確了元素的大小不會超過數組的長度,所以定義數組長度設爲num.length。
遍歷數組,比如num[5]的元素是3,那麼新數組下標爲3處就加一,表示3已經出現過一次。
這樣時間複雜度是O(n)空間複雜度是O(n)
public int findRepeatNumber(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int[] count = new int[nums.length];
for (int i= 0; i < nums.length ; i++) {
if (count[nums[i]] != 0) {
return nums[i];
}
count[nums[i]] ++;
}
return -1;
}
法三:不開闢額外數組
核心思想與法二相同,只是這次沒有重新開闢新的空間,而是對原來的數組進行了修改。
正常情況下排序後,下標爲i處的元素就是i 。
所以,遍歷一遍數組,如果i處的元素不是i 那我們就把它交換到nums[i]處,一次不一定可以使得nums[i] = i ,那就使用while循環,直到滿足i處元素就是i。
例如:
對於i=0,第一次nums[0] = 2
,就和nums[2]
處元素1交換交換
交換後,nums[0] = 1就和nums[1]處元素3交換
交換後,nums[0] = 3就和nums[3]處元素0交換
至此,nums[0]就等於0
如此循環。
如果下次交換時碰到要交換過去的位置上的元素剛好等於自己,那就找到了。由於沒有開闢新數組,時間複雜度O(n)空間複雜度O(1)
雖然for循環又嵌套了while循環,但是每一個數來到它應該在的位置以後,位置就不會再變化。
public int findRepeatNumber(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
for (int i = 0; i < n; i ++) {
while (nums[i] != i) {
if (nums[i] == nums[nums[i]]) {
return nums[i];
}
int tmp = nums[i];
nums[i] = nums[tmp];
nums[tmp] = tmp;
}
}
return -1;
}