JavaScrip 判斷數組重複元素 經典面試算法

如何找出數組中唯一的重複元素

題目描述
數字1~1000放在含有1001個元素的數組中,其中只有唯一的一個元素值重複,其他數字均只出現一次。設計一個算法,將重複元素找出來,要求每個數組元素只能訪問一次。如果不使用輔助存儲空間,能否設計一個算法實現?
分析:從題目的描述可以發現,本題的目標就是在一個有且僅有一個元素值重複的數組中找出這個唯一的重複元素,而限定條件就是,每個數組元素只能訪問一次,並且不許使用輔助存儲空間

方法1

時間複雜度爲O(N),空間複雜度爲O(1)
思路:我們可以將數組所有元素求和。然後將1~1000累加求和。兩個數相減,差就是重複的數。

let arr = []
let sumArr = 0
for (let i = 0; i < arr.length; i++) {
	sumArr += arr[i]
}
let sumNum = (1 + 1000) * 1000 / 2
result = sumArr - sumNum

注意:這個方法只適用於給定的數比較小,數太大會溢出!!!


方法2

時間複雜度爲O(N),並且沒有申請輔助的存儲空間。
思路:可以採用位運算中異或的方法。根據異或運算的性質可知,當相同元素異或時,其運算結果爲0;當相異元素異或時,其運算結果爲非0。任何數與數字0進行異或運算,其運算結果爲該數。本題中,正好可以使用到此方法,即將數組裏的元素逐一進行異或運算,得到的值再與數字1、2、3、…、N進行異或運算,得到的最終結果即爲所求的重複元素。

			let arr = [1, 3, 4, 2, 5, 3, 6, 9, 8, 7]
			let result = arr[0]
			if (arr.length == 0) {
				console.log("數組空")
			}
			for (let i = 1; i < arr.length; i++) {
				result ^= arr[i]
				result ^= i
			}
			console.log(result)

方法3

如果題目沒有對是否可以使用輔助數組做限制的話,那麼最簡單的方法就是使用Hash法。
時間複雜度爲O(N),空間複雜度爲O(N)。
思路:首先定義一個長度爲1000的Hash數組,將Hash數組中的元素值都初始化爲0,然後將原數組中的元素逐一映射到該Hash數組中。當對應的Hash數組中的值爲0時,則置該Hash數組中該處的值爲1;當對應的Hash數組中該處的值爲1時,則表明該位置的數在原數組中是重複的,輸出即可。

			function H(arr){
				let hash = []
				if (arr.length == 0) {
					console.log("數組空")
				}
				for (let i = 0; i < arr.length; i++) {
					if(hash[arr[i]]===1){
						return arr[i]
					}else if (hash[arr[i]] !== 1) {
						hash[arr[i]] = 1
					}
				}
			}

注意:方法3是一種典型的以空間換時間的方法,很顯然,在題目沒有明確限制的情況下,上述方法不失爲一種好方法。但是由於題目要求不能用額外的輔助空間,所以上述方法不可取


判斷數組中是否有重複值

方法1

同上一題,如果題目對空間複雜度沒有限制,就用哈希表。

方法2

在這裏插入圖片描述
不能用哈希表時候,那你就只能排序,排序之後重複的值是相鄰的,遍歷就好了。
那麼問題就來到了排序這邊,哪個排序空間複雜度爲O(1)

空間複雜度

  • O(1):插入排序、選擇排序、冒泡排序、堆排序
  • O (logN)-O(N):快速排序
  • O(N):歸併排序
  • 特例:希爾排序時間複雜度取決於你的步長怎麼取。時間複雜度在 O(nlog2n)到O(n2)之間

時間複雜度

  • O(n2):插入排序、冒泡排序、選擇排序
  • O(nlog2n):快速排序、堆排序、歸併排序
  • O(n):基數排序、計數排序
  • 特例:堆排序如果用遞歸方法寫,那空間複雜度就是O (logN),如果不用遞歸就是O(1)

綜合起來時間複雜度和空間複雜度之後就發現,最優的方法就是用改良後的堆排序。
🙌我是小垃圾,我還不會優化之後的堆排序,等我會了我再補充。


我是蘿莉安💖,晚安,今天也是努力學習的一天。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章