子集和问题 算法_LeetCode刷题实战90:子集 II
算法的重要性,我就不多說了吧,想去大廠,就必須要經(jīng)過基礎(chǔ)知識(shí)和業(yè)務(wù)邏輯面試+算法面試。所以,為了提高大家的算法能力,這個(gè)公眾號(hào)后續(xù)每天帶大家做一道算法題,題目就從LeetCode上面選 !
今天和大家聊的問題叫做?子集 II,我們先來看題面:
https://leetcode-cn.com/problems/subsets-ii/
Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
題意
給定一個(gè)可能包含重復(fù)元素的整數(shù)數(shù)組 nums,返回該數(shù)組所有可能的子集(冪集)。說明:解集不能包含重復(fù)的子集。樣例輸入: [1,2,2]
輸出:[
??[2],[1],[1,2,2],[2,2],[1,2],[]
]
解題
https://www.cnblogs.com/techflow/p/13489811.html題解
全排列的問題也好,獲取子集也好,這些問題都已經(jīng)算是老生常談了,我們之前做過不少。這些問題經(jīng)過轉(zhuǎn)化之后,本質(zhì)上還是搜索問題。我們?cè)跇颖究臻g當(dāng)中搜索所有合法的解,存儲(chǔ)起來。這道題的前身LeetCode78題用的正解也是搜索的解法,對(duì)于使用搜索算法來解這道題問題不大,但問題是針對(duì)數(shù)組當(dāng)中的重復(fù)元素我們應(yīng)該怎么樣來處理。最簡單也是最容易想到的方法當(dāng)然是先把所有的子集全部找到之后,我們?cè)龠M(jìn)行去重。如果采用這樣的方法,還有一個(gè)便利是我們可以不用遞歸,而是可以通過二進(jìn)制枚舉的方法獲取所有的子集。但也有一個(gè)問題,問題就是復(fù)雜度。我們把集合當(dāng)中的每一個(gè)數(shù)字都看成是獨(dú)立的,那么對(duì)于每一個(gè)數(shù)字來說都有取和不取兩種方案。對(duì)于n個(gè)數(shù)字來說,方案總數(shù)當(dāng)然就是。并且我們還需要對(duì)這個(gè)集合進(jìn)行去重,這帶來的開銷可想而知。當(dāng)然針對(duì)這個(gè)問題我們也有解決方案比如可以用hash算法將一個(gè)集合hash成一個(gè)數(shù),如果hash值一樣說明集合的構(gòu)成相同。這樣我們就可以通過對(duì)數(shù)字去重來實(shí)現(xiàn)集合去重了。但這樣仍然不是完美的,首先hash算法也不是百分百可靠的,也可能會(huì)出現(xiàn)hash值碰撞的情況。其次,這種方案的實(shí)現(xiàn)復(fù)雜度也很大,我們找出所有集合之后再通過hash算法進(jìn)行過濾,整個(gè)過程非常麻煩。很明顯,這題一定還存在更好的方法。既然事后找補(bǔ)不靠譜,那么我們可以試著事前避免。也就是說我們?cè)谒阉魉凶蛹臅r(shí)候就設(shè)計(jì)一種機(jī)制可以過濾掉重復(fù)的集合或者是保證重復(fù)的集合不會(huì)出現(xiàn)。我們可以分析一下重復(fù)的集合出現(xiàn)的原因,兩個(gè)集合完全一樣,說明其中的元素構(gòu)成完全一致。元素的構(gòu)成一致又有兩種可能,第一種是重復(fù)的獲取,比如[1, 3],我們先拿1再拿3和先拿3再拿1本質(zhì)上是一樣的。還有一種可能是元素的重復(fù)導(dǎo)致的集合重復(fù),比如[1, 3]假如我們候選的1不止一個(gè),那么拿不同的1也會(huì)被認(rèn)為是不同的方案。針對(duì)第一種情況出現(xiàn)的重復(fù)非常簡單,我們可以對(duì)元素進(jìn)行排序,之后限定拿取元素的順序。只能從左拿到右,不能先拿右邊的元素再回頭拿左邊的元素,這樣就禁止了第一種情況導(dǎo)致的重復(fù)。這個(gè)方法我們?cè)?jīng)在很多問題當(dāng)中用到過,就不詳細(xì)介紹了。下面來說說第二種情況,就是重復(fù)元素導(dǎo)致的重復(fù)集合。這一點(diǎn)需要結(jié)合代碼來仔細(xì)說明,我們來看一段經(jīng)典的搜索代碼:def?dfs(cur, subset):????for?i in?range(cur, n):
????????nxt = subset + [nums[i]]
????????ret.append(nxt)
????????dfs(i+1, nxt)
class?Solution:def?subsetsWithDup(self, nums: List[int])?-> List[List[int]]:# 對(duì)元素排序,將重復(fù)的元素挨在一起
????????nums = sorted(nums)
????????ret = [[]]
????????n = len(nums)def?dfs(cur, subset):????# 上一次選擇的元素,一開始置為None
????????????last = Nonefor?i in?range(cur, n):if?i == cur or?nums[i] != last:# 存儲(chǔ)集合
????????????????????nxt = subset + [nums[i]]
????????????????????ret.append(nxt)# 更新last
????????????????????last = nums[i]
????????????????????dfs(i+1, nxt)
????????dfs(0, [])return?ret
上期推文:
LeetCode50-80題匯總,速度收藏!LeetCode刷題實(shí)戰(zhàn)81:搜索旋轉(zhuǎn)排序數(shù)組 IILeetCode刷題實(shí)戰(zhàn)82:刪除排序鏈表中的重復(fù)元素 IILeetCode刷題實(shí)戰(zhàn)83:刪除排序鏈表中的重復(fù)元素LeetCode刷題實(shí)戰(zhàn)84:?柱狀圖中最大的矩形LeetCode刷題實(shí)戰(zhàn)85:最大矩形LeetCode刷題實(shí)戰(zhàn)86:分隔鏈表LeetCode刷題實(shí)戰(zhàn)87:擾亂字符串LeetCode刷題實(shí)戰(zhàn)88:合并兩個(gè)有序數(shù)組LeetCode刷題實(shí)戰(zhàn)89:格雷編碼總結(jié)
以上是生活随笔為你收集整理的子集和问题 算法_LeetCode刷题实战90:子集 II的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ctf的php,CTF中常见的PHP漏洞
- 下一篇: 二阶龙格库塔公式推导_带你走进最美数学公