日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

在数组中找重复数、只出现一次的数或丢失数的题目(Leetcode题解-Python语言)

發布時間:2023/12/4 python 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在数组中找重复数、只出现一次的数或丢失数的题目(Leetcode题解-Python语言) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在一維數組中的考察中,最常見的就是找出數組中的重復數、只出現一次的數或者丟失(消失)數等等。

一般來說,首先想到的就是用哈希表集合)來記錄出現過的數,基本所有的題都可以用集合來做,而技巧性在于有時可以把原數組自身作為哈希表
其次就是位運算,原理是相同的數做異或運算 ^ 會得到0,而一個數與0做異或會得到這個數本身
最后,在排好序或者對空間要求為O(1)但又不能修改原數組的情況下,二分查找也是一種方法。

136. 只出現一次的數字(找出一個只出現一次的數字

class Solution:def singleNumber(self, nums: List[int]) -> int:ans = set()for num in nums:if num in ans:ans.remove(num)else:ans.add(num)return ans.pop()

雖然可以用集合解決,但是此題最優的做法是位運算,數組里面所有相同的數異或會得到0,而那個只出現一次的數再與0做異或,直接得到結果本身,代碼如下:

class Solution:def singleNumber(self, nums: List[int]) -> int:ans = nums[0]for i in range(1, len(nums)):ans = ans ^ nums[i]return ans

217. 存在重復元素(是否存在重復元素

class Solution:def containsDuplicate(self, nums: List[int]) -> bool:temp = set()for num in nums:if num in temp:return Trueelse:temp.add(num)return False

劍指 Offer 03. 數組中重復的數字(找出一個重復元素

class Solution:def findRepeatNumber(self, nums: List[int]) -> int:temp = set()for num in nums:if num in temp:return numelse:temp.add(num)return -1

用集合輕松解決,但是可以不使用額外的集合,而是將原數組本身當作集合,通過交換使得數組的值與索引(下標)一一對應,若出現兩個值對應同一個索引,即為重復的元素。

class Solution:def findRepeatNumber(self, nums: [int]) -> int:i = 0while i < len(nums):if nums[i] == i: # 值與索引已經相同,跳過i += 1continueif nums[i] == nums[nums[i]]: # 值與值所指向下標的值一樣,說明是重復數return nums[i]nums[nums[i]], nums[i] = nums[i], nums[nums[i]]return -1

注意: Python 中, a, b = c, d操作的原理是先暫存元組 (c,d) ,然后 “按左右順序” 賦值給 a 和 b 。因此,若寫為 nums[i], nums[nums[i]] = nums[nums[i]], nums[i],則 nums[i] 會先被賦值,之后 nums[nums[i]] 指向的元素則會出錯。

260. 只出現一次的數字 III(劍指 Offer 56 - I. 數組中數字出現的次數)(找出兩個只出現一次的數字

回想到,對所有數字進行異或就可以得到結果,本題中其余數字也是出現兩次,區別在于有兩個數字只出現一次。在這里,我們會希望這兩個數字分別出現在兩組中,對這兩組都進行異或,這樣就能得到答案了。怎么做呢?線索在于,對所有數字進行異或后的結果,考慮其每一位取值的意義,如果為0,說明這兩個數字的這一位相同,如果為1則不相同。

找到第一位為1的,說明這兩個數在這一位上一個為1、一個為0。以此我們可以把數組分為兩部分,這兩個數各自存在于這兩部分中,劃分的依據就是這一位的取值。至于其他出現兩次的數,在分組時相同的數一定在同一組,因此對這兩組都進行全部異或,出現兩次的數會抵消,最后剩下這兩個數字。

class Solution:def singleNumber(self, nums: List[int]) -> List[int]:# 全部異或ret = reduce(lambda x, y: x ^ y, nums) # reduce(二元函數, 可迭代對象)h = 1while h & ret == 0: # 從右邊開始找第一位為1的(兩個數不同的位)h <<= 1a, b = 0, 0# 分別異或for n in nums:if n & h: # n 在這一位是 1,一個組a ^= nelse: # n 在這一位是 0,另一個組b ^= nreturn [a, b]

137. 只出現一次的數字 II(劍指 Offer 56 - II. 數組中數字出現的次數 II)(劍指 Offer II 004. 只出現一次的數字 )(找出一個只出現一次的數字,然而其他數字都出現三次

class Solution:def singleNumber(self, nums: List[int]) -> int:counter = collections.Counter(nums)ans = [num for num, val in counter.items() if val == 1]return ans[0]

這一題用集合的話,還不能簡單地出現過就 pop,沒出現過就 push,因為重復數字是出現三次的,所以應該用 Counter 來解決,更加優化的思路是借鑒數字電路的:

class Solution:def singleNumber(self, nums: List[int]) -> int:a = 0b = 0for i in range(len(nums)):b = (b ^ nums[i]) & ~aa = (a ^ nums[i]) & ~breturn b

思路是設置一個狀態機,有 a、b 兩個記錄器:第一次碰到數字 x 時,記錄器 b 記錄下來,記錄器 a 為 0;第二次碰到數字 x 時,記錄器 a 記錄下來,記錄器 b 為 0;第三次碰到數字 x 時,兩個記錄器都為 0。這樣遍歷所有數字之后,出現三次的為 0,出現一次的就存放在記錄器 b 中。

實現記錄器 b 的方法:第一次碰到 x 記錄,第二次碰到 x 變 0,實際上就是異或 b = b ^ x,但是第三次碰到 x 時 b 還是0,區別就只在于記錄器 a 的值為 x ,而第一二次時 a 都為0,因此是 b = (b ^ x) & ~a ,對于記錄器 a 同理。

268. 丟失的數字(劍指 Offer 53 - II. 0~n-1中缺失的數字)(找出 0 - n 范圍中沒出現的那一個數

class Solution:def missingNumber(self, nums: List[int]) -> int:n = len(nums)ans = 0for i in range(n):ans = ans ^ nums[i] ^ ians ^= (i + 1) # 正常的數組,包括 nreturn ans

方法一:正常的數組求和減去缺失的數組求和,差值就是缺失的數;

方法二:正常的數組與缺失的數組做異或,相同的數會異或為0,剩下的就是缺失的數。

448. 找到所有數組中消失的數字(找出多個 1 - n 范圍中沒出現的數

class Solution:def findDisappearedNumbers(self, nums: List[int]) -> List[int]:n = len(nums)for num in nums:x = (num - 1) % n # 由于是表示下標,所以 num - 1nums[x] += n # 加上 n 不會改變其對 n 取余數的結果ans = [i + 1 for i, num in enumerate(nums) if num <= n] # 沒有被加上 n 的下標就是數組里沒有的return ans

由于是多個數沒出現,所以不能簡單地用異或解決,用集合固然可以做,但是更優化地是把原數組本身作為集合,利用值與索引之間的映射關系來找出目標數。此題中,我們把數組中出現了的值對應的下標都加上 n,則沒有被加上 n 的下標就是數組里沒有的。

442. 數組中重復的數據(找出多個 1 - n 范圍中重復出現的數

class Solution:def findDuplicates(self, nums: List[int]) -> List[int]:n = len(nums)for num in nums:x = (num - 1) % n # 由于是表示下標,所以 num - 1nums[x] += n # 加上 n 不會改變其對 n 取余數的結果ans = [i + 1 for i, num in enumerate(nums) if num > n * 2] # 被加上2次 n 的下標就是數組里重復的數return ans

與上一題同理,利用值與索引的對應關系,找出在數組中出現兩次的值(其對應下標的值被兩次加上了 n)。

287. 尋找重復數(找出唯一的重復出現的數

class Solution:def findDuplicate(self, nums: List[int]) -> int:left = 1right = len(nums) - 1while left < right:mid = left + (right - left) // 2 cnt = 0 # 記錄小于等于mid的元素個數for num in nums:if num <= mid:cnt += 1if cnt > mid:right = midelse:left = mid + 1return left

這題比較特別,規定了不能修改數組 nums 且只用常量級 O(1) 的額外空間。給定一個包含 n + 1 個整數的數組,其數字都在 1 到 n 之間,只有一個數字是重復的。因此,對于某個數字 x 來說,正常來說小于等于 x 的數字應該有 x 個,例如有1、2、3、4共4個數字小于等于4,如果大于4了,則說明1、2、3、4其中有一個數字重復了,所以右邊界左移,反之左邊界右移。此為二分數值型

540. 有序數組中的單一元素(劍指 Offer II 070. 排序數組中只出現一次的數字)(找出有序數組的唯一不重復的數

class Solution:def singleNonDuplicate(self, nums: List[int]) -> int:left = 0right = len(nums) - 1while left < right:mid = left + (right - left) // 2if mid % 2 == 1: # 只考慮偶數下標mid -= 1if nums[mid] == nums[mid + 1]: # 如果它和下一個數相同,說明還正常,單一元素在右邊區間left = mid + 2else:right = midreturn nums[left]

這題用集合可以做到 O(n) 的時間,但是用二分可以做到 O(logn)。注意到,由于數組中只有一個不重復的數,所以總長度一定是奇數,而首尾下標都為偶數。又因為數組是有序的,所以重復數都是兩兩一起出現,且正常的情況都是(偶數索引,奇數索引),只有當出現那一個不重復的數(偶數索引),索引才會變成(奇數,偶數)。所以用二分索引法找到每個偶數下標,如果它和下一個數相同,則說明排序還是正常的,即單一元素在右邊區間;否則,則說明排序已經不正常,單一元素在左邊區間。

41. 缺失的第一個正數(找出數組中沒有出現的最小的正整數

class Solution:def firstMissingPositive(self, nums: List[int]) -> int:n = len(nums)for i in range(n):if nums[i] <= 0:nums[i] = n + 1for i in range(n):num = abs(nums[i])if num <= n:nums[num - 1] = -abs(nums[num - 1])for i in range(n):if nums[i] > 0:return i + 1return n + 1

用集合可以做,但是題目要求時間復雜度為 O(n) 并且只使用常數級別額外空間。實際上,對于一個長度為 N 的數組,其中沒有出現的最小正整數只能在 [1, N+1] 中。這是因為如果 [1, N] 都出現了,那么答案是 N+1,否則答案是 [1, N] 中沒有出現的最小正整數。所以我們的思路就是:不考慮負數,將它們設置為 n + 1;對于在 [1, N] 中的數(此時之前的負數為 n + 1,不會被考慮),將其值對應下標的數變為負(作為已經出現過了的標志);最后找出第一個不是負數的,其對應下標就是沒出現的,即為答案。若所有都出現過,答案則為 n + 1。

總結

以上是生活随笔為你收集整理的在数组中找重复数、只出现一次的数或丢失数的题目(Leetcode题解-Python语言)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。