劍指Offer 051 陣列中重複的數字

2021-07-12 05:15:35 字數 3770 閱讀 3905

牛客oj:陣列中重複的數字

九度oj:未收錄

github**: 051-陣列中重複的數字

csdn題解:劍指offer–051-陣列中重複的數字

牛客oj

九度oj

csdn題解

github**

051-陣列中重複的數字

未收錄劍指offer–051-陣列中重複的數字

051-陣列中重複的數字

題目描述

在乙個長度為n的陣列裡的所有數字都在0到n-1的範圍內。

陣列中某些數字是重複的,但不知道有幾個數字是重複的。

也不知道每個數字重複幾次。請找出陣列中任意乙個重複的數字。

例如,如果輸入長度為7的陣列,那麼對應的輸出是重複的數字2或者3。

樣例輸入

2, 3, 1, 0, 2, 5, 3

2, 1, 3, 1, 4

樣例輸出

bool checkvalidity(int *numbers, int length)

// 元素必須在[0, n-1]的範圍

for(int i = 0; i < length; i++)

}return

true;

}

最簡單的思路就是先把輸入的陣列排序。從排序的陣列中找出重複的數字就是個很容易的事情了。只需要從頭向尾掃瞄一遍排序好的陣列即可。

對乙個陣列排序的時間複雜度是o(

nlog

n)

掃瞄乙個排序好的陣列發現重複的數字的時間複雜度是o(

n)

class solution

sort(numbers, numbers + length); // 對陣列進行排序

int i = 0;

bool isdup = false;

*duplication = -1;

// 掃瞄一遍陣列發現重複的數字

for(i = 0; i < length - 1; i++)

}return isdup;

}};

當然我們用hashtabble也可以實現,

hashtable中可以很方便的查詢到某個元素是否存在,時間複雜度o(

n),空間複雜度o(

n)

class solution

set s;

bool isdup = false;

*duplication = -1;

for(int i = 0; i < length; i++)

s.insert(numbers[i]);

}return isdup;

}};

hashtable的方式是在優化查詢的過程,因為hashtable查詢的時間複雜度為o(

1),那麼我們繼而聯想到,如果不設hash,直接用乙個用乙個陣列flag當前標識,記錄某個元素是否出現,

flag[i] =0標識元素i未出現,

flag[i] =1標識元素i出現

這樣也可以在o(

1)的時間內實現判斷

class solution

int flags[length];

memset(flags, 0, sizeof(flags));

for(int i = 0; i < length; i++)

else

}return

false;

}};

我們採用了乙個以空間換時間的方式, 但是有沒有什麼辦法能夠優化空間上的消耗呢?

因為我們需要的只是乙個標識, 0或者1,那麼我們完全沒必要乙個整數來做標識,

因此可做如下優化

用乙個n位的單元來儲存即可, 每一位都是乙個標識

這種方法可以把空間消耗將低, 但是還是需要額外的空間,那麼有沒有不需要空間消耗的方法呢?

我們可以看到陣列中元素的大小都在[0-n)這個區間內, 都是正數,那麼他們的符號位對我們來說就是無關緊要的, 因此我們直接拿符號位當成我們的標識位就行了

numbers[i]符號位為0表示數字i沒有重複

numbers[i]符號位為1標識數字i重複

#define set_symbol_bit(num)  ((num) |= (1 << 31))       /*  設定符號位為1 */

#define get_origin_num(num) ((num) & (~(1 << 31))) /* 獲取到源資料 */

#define get_symbol_bit(num) (((num) >> 31) & 1) /* 獲取符號位(標識)*/

class solution

for(int i = 0; i < length; i++)

else

};

跟標識法類似, 如果不借助外部輔助空間,那麼我們只能在陣列內部下功夫,又能設定標識,又能恢復資料(不破壞資料)的方式,前面我們用符號位作為標識的方法就是通過符號位,即判斷了是否存在,又可以通過符號位的反轉重新恢復資料,那麼有沒有其他類似的方法呢?

我們想到我們的資料都是[0, n)這個區間的,那麼我們採用類似與移碼的方法,讓資料加上或者減去乙個固定的偏移量,這樣就可以即標識資料,又不損壞資料,為了能夠區分出資料,這個偏移必須大於n,這樣我們的原資料與標識資料存在一一對映關係。

[0, n-1] -=>+偏移n-=> [n, 2n-1]

class solution

for(int i = 0; i < length; i++)

else

}return

false;

}};

劍指offer上提供的方法,這種方法採用交換的方法

我們考慮如果每個數字都置出現一次,那麼此時是最完美的,每乙個下標i對應元素numbers[i],也就是說我們對於陣列中的每個元素numbers[i]都把它放在自己應該在的位置上numbers[numbers[i]]上, 如果我們發現有兩個元素想往同乙個位置上放的時候,說明此元素必然重複

即如下的過程

如果numbers[i] == i, 那麼我們認為number[i]這個元素是在自己的位置上的

否則的話, numbers[i]這個元素就應該在numbers[numbers[i]]這個位置上, 於是我們交換numbers[i]和numbers[numbers[i]]

重複操作1, 直到number[i]== i, 則繼續操作下乙個位置的元素, 或者numbers[i] == numbers[numbers[i],元素重複

class solution

for(int i = 0; i < length; i++)

debug <<"swap numbers["

<"] and numbers["

<"]"

<"numbers["

<"] = "

<" is equal to it's index = "

false;

}};

劍指Offer (陣列)陣列中重複的數字

題目鏈結 題目描述 在乙個長度為n的陣列裡的所有數字都在0到n 1的範圍內。陣列中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每個數字重複幾次。請找出陣列中任意乙個重複的數字。例如,如果輸入長度為7的陣列,那麼對應的輸出是第乙個重複的數字2。解決方法class solution retur...

劍指offer 陣列 陣列中重複的數字

在乙個長度為n的陣列裡的所有數字都在0到n 1的範圍內。陣列中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每個數字重複幾次。請找出陣列中任意乙個重複的數字。例如,如果輸入長度為7的陣列,那麼對應的輸出是第乙個重複的數字2。遍歷每乙個數字,在其後的數字中查詢是否有含有相同的數字 coding...

劍指Offer 陣列中的重複陣列

public boolean duplicate int numbers,int length,int duplication arrays.sort numbers for int i 0 i下面來看看乙個比較,交換的過程 原始陣列 第一次 i 0 陣列第0個元素是2,與下標不等,然後與下標為2的...