這題是一題把陣列當成類似 linked list 的題目,目標是找到陣列中重複的元素,因它只對陣列進行了兩次循環,而每次循環都是線性時間的運作,時間複雜度可達 O(n)
,這裡有 JAVA 和 Python 的寫法。
Given an array of integers
nums
containingn + 1
integers where each integer is in the range[1, n]
inclusive.
There is only one repeated number innums
, return this repeated number.
You must solve the problem without modifying the arraynums
and uses only constant extra space.
給定一個整數陣列
nums
含有n + 1
個整數,每個整數都在[1, n]
範圍包含裡。nums
中只有一個重複的數字,回傳這個重複的數字。
你必須在不能修改nums
的情況下解決這個問題,而且只能使用常數的記憶體空間。
題目連結:https://leetcode.com/problems/find-the-duplicate-number/
1 <= n <= 105
nums.length == n + 1
1 <= nums[i] <= n
All the integers in nums
appear only once except for precisely one integer which appears two or more times.
Input: nums = [1,3,4,2,2]
Output: 2
Input: nums = [3,1,3,4,2]
Output: 3
暴力的解法是利用雙迴圈,找出相等的元素後就是答案,結果超過時間限制 (不採用)
另一種解法,運用 HashSet 方法的特性,找出不能出現的元素
- 循環 nums 陣列,把每個元素添加到 HashSet 中
- 如果發現某個元素已經存在於 HashSet 中,那麼這個元素就是重複的
- 回傳這個元素
第三種解法是使用鏈表的特性,在鏈表內的元素不會有重複,有重複的話會形成一個環
- 把當前的元素,當成下一個元素的 index,變成一個類似 linked list 的鏈表
- 然後設定一組快慢指針,慢指針走一步,快指針走兩步,在鏈表中有重複的元素,快指針會先走到有重複元素的環內,慢指針也會走到有重複元素的環內,這時如果快慢指針都走到相同的元素,代表這個元素就是我們要找的重複的元素
- 例如走過 2 這個元素,後面又再次遇到 2 的時候,代表 2 是重複的元素,然而會形成一個環,在這個有重複元素的還內一直打轉
- 另外設定第三個指針檢查,用意是找出環的頭,無論用慢指針或快指針去和檢查指針比對都行,快慢指針是一樣的元素
while 迴圈從 0 開始走,到 3 的時候已經遇到一個 2 了,繼續走到 4 的時候又遇到一個 2
// 暴力的解法是利用雙迴圈,找出相等的元素後就是答案,結果超過時間限制 (不採用)
class Solution {
public int findDuplicate(int[] nums) {
for (int i = 0; i < nums.length; i++) {
for(int j = i + 1; j < nums.length; j++) {
if (nums[i] == nums[j]){
return nums[i];
};
};
};
return -1;
};
};
// 另一種解法,運用 HashSet 方法的特性,找出不能出現的元素
class Solution {
public int findDuplicate(int[] nums) {
HashSet<Integer> set = new HashSet<>(); // 集合
for(int num : nums) {
// 添加進去時會判斷有沒有 (重複元素不會被添加)
if(!set.add(num)) {
return num; // 回傳當下這個元素
}
}
return -1;
}
}
// 第三種解法是使用鏈表的特性,在鏈表內的元素不會有重複,有重複的話會形成一個環
class Solution {
public int findDuplicate(int[] nums) {
int slow = 0; // 慢指針
int fast = 0; // 快指針
int check = 0; // 確認指針
while( true ){
slow = nums[slow]; // 取得 index 位置(走一步)
fast = nums[nums[fast]]; // 取得 index 位置後,從位置再取一次新的位置 (等於走兩步)
// 如果快慢指針一樣
if( slow == fast ){
break;
}
}
// 找出循環的頭
while( true ){
slow = nums[slow];
check = nums[check]; // 檢查指針
// 如果慢指針和檢查指針一樣
if( slow == check ){
break;
}
}
return check;
}
}
使用了和 Java 一樣的邏輯執行,換成 Python 的寫法。
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
slow = 0
fast = 0
check = 0
while True:
slow = nums[slow] # 取得 index 位置(走一步)
fast = nums[nums[fast]] # 取得 index 位置後,從位置再取一次新的位置 (等於走兩步)
# 如果快慢指針一樣
if slow == fast:
break
# 找出循環的頭
while True:
slow = nums[slow]
check = nums[check]
# 如果慢指針和檢查指針一樣
if slow == check:
break
return check
Language | Runtime | Memory |
---|---|---|
Java | 4ms | 59.49MB |
Python | 520ms | 30.95MB |
(新手上路,如有錯誤請友善告知,感謝)
Blog
https://chris81051.github.io/2023/09/10/LeetCode-287-Find-the-Duplicate-Number-Java-Python/
有分享技術文章、科技新聞、日常生活,歡迎一起討論