Python算法-子集問題

46. 全排列

給定一個不含重復數(shù)字的數(shù)組 nums 思杯,返回其 所有可能的全排列 挎狸。你可以 按任意順序 返回答案武花。

輸入:nums = [1,2,3]
輸出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        path = []
        def backtracing(nums):
            # 終止條件:當路徑上的元素數(shù)量等于最大值
            if len(path) == len(nums):
                res.append(path[:])
                return

            for i in range(len(nums)):
                if nums[i] not in path:
                    path.append(nums[i])
                    # 遞歸搜索
                    backtracing(nums)
                    # 撤銷選擇
                    path.pop()
        backtracing(nums)
        return res
47. 全排列 II

給定一個可包含重復數(shù)字的序列 nums 修赞,按任意順序 返回所有不重復的全排列询件。

輸入:nums = [1,1,2]
輸出:
[[1,1,2],
[1,2,1],
[2,1,1]]

# 對于數(shù)組中包含重復數(shù)字杆融,需要對重復的數(shù)字提前進行標注楞卡,在訪問時及時去重
class Solution:
    res = []
    path = []
    # 回溯算法
    def backtracing(self, nums: List[int], visited: List[bool]):
        # 遞歸的終止條件
        if len(nums) == len(self.path):
            self.res.append(self.path[:])
            return 

        for i in range(len(nums)):
            # 需要及時去重,如果相同元素之前訪問過,則跳過
            if i > 0 and nums[i] == nums[i-1] and not visited[i-1]:
                continue
            # 元素沒有訪問過
            if not visited[i]:
                # 訪問之后需要進行標記
                visited[i] = True
                self.path.append(nums[i])
                self.backtracing(nums, visited)
                self.path.pop()
                # 回溯之后對元素進行恢復
                visited[i] = False

    # 主函數(shù)
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        # 清除緩存
        self.res.clear()
        self.path.clear()
        # 需要對nums進行排序
        nums.sort()
        # 用于記錄是否訪問過相同元素
        visited = [False]*len(nums)
        self.backtracing(nums, visited)
        return self.res
90. 子集 II

給你一個整數(shù)數(shù)組 nums 蒋腮,其中可能包含重復元素淘捡,請你返回該數(shù)組所有可能的子集(冪集)。
解集 不能 包含重復的子集池摧。返回的解集中案淋,子集可以按 任意順序 排列。

示例 1:
輸入:nums = [1,2,2]
輸出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

class Solution:
    def backtrace(self, nums, index, res, path):
        # 空數(shù)組
        res.append(path[:])
        # 從第0個位置開始险绘,進行深度優(yōu)先搜索
        for i in range(index, len(nums)):
            if i > index and nums[i] == nums[i-1]:
                continue
            path.append(nums[i])
            self.backtrace(nums, i+1, res, path)
            path.pop()


    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        # 首先對數(shù)組排序
        nums.sort()
        res, path = [], []
        self.backtrace(nums, 0, res, path)
        return res
784. 字母大小寫全排列

給定一個字符串 s 踢京,通過將字符串 s 中的每個字母轉變大小寫,我們可以獲得一個新的字符串宦棺。
返回 所有可能得到的字符串集合 瓣距。以 任意順序 返回輸出。

輸入:s = "a1b2"
輸出:["a1b2", "a1B2", "A1b2", "A1B2"]

# 大小寫轉換
class Solution:
    def dfs(self, s, i, path, ans):
        # 終止條件
        if i == len(s):
            ans.append(path[:])
            return 

        self.dfs(s, i+1, path+s[i], ans)
        # 當字符為小寫字母代咸,轉換為大寫并添加
        if ord('a') <= ord(s[i]) <= ord('z'):
            self.dfs(s, i+1, path + s[i].upper(), ans)
        # 當字符為大寫字母是蹈丸,轉換為小寫并添加
        elif ord('A') <= ord(s[i]) <= ord('Z'):
            self.dfs(s, i+1, path + s[i].lower(), ans)

    def letterCasePermutation(self, s: str) -> List[str]:
        ans, path = [], ''
        self.dfs(s, 0, path, ans)
        return ans
39. 組合總和

給你一個 無重復元素 的整數(shù)數(shù)組 candidates 和一個目標整數(shù) target ,找出 candidates 中可以使數(shù)字和為目標數(shù) target 的 所有 不同組合 呐芥,并以列表形式返回逻杖。你可以按 任意順序 返回這些組合。
candidates 中的 同一個 數(shù)字可以 無限制重復被選取 思瘟。如果至少一個數(shù)字的被選數(shù)量不同荸百,則兩種組合是不同的。
對于給定的輸入滨攻,保證和為 target 的不同組合數(shù)少于 150 個够话。

輸入:candidates = [2,3,6,7], target = 7
輸出:[[2,2,3],[7]]
解釋:
2 和 3 可以形成一組候選,2 + 2 + 3 = 7 光绕。注意 2 可以使用多次女嘲。
7 也是一個候選, 7 = 7 诞帐。
僅有這兩種組合欣尼。

class Solution:
    path = []
    res = []
    def backtracing(self, candidates: List[int], target:int, sum_all:int, start_index:int):
        # 遞歸的終止條件
        if sum_all > target:
            return
        if sum_all == target:
            self.res.append(self.path[:])
            return 
        
        # 開始遍歷查找
        for i in range(start_index, len(candidates)):
            # 循環(huán)終止條件
            if sum_all + candidates[i] > target:
                break

            sum_all += candidates[i]
            self.path.append(candidates[i])
            # 回溯
            self.backtracing(candidates, target, sum_all, i)
            sum_all -= candidates[i]
            self.path.pop()

    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        self.path.clear()
        self.res.clear()
        candidates.sort()
        self.backtracing(candidates, target, 0, 0)
        # print(self.res)
        return self.res
40. 組合總和 II

給定一個候選人編號的集合 candidates 和一個目標數(shù) target ,找出 candidates 中所有可以使數(shù)字和為 target 的組合停蕉。
candidates 中的每個數(shù)字在每個組合中只能使用 一次 愕鼓。
注意:解集不能包含重復的組合。

輸入: candidates = [10,1,2,7,6,1,5], target = 8,
輸出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

# 本題主要考慮去重
class Solution:
    res = []
    path = []
    def backtracing(self, candidates: List[int], target: int, sum_all: int, start_index: int):
        # 遞歸的終止條件
        if sum_all > target:
            return 
        if sum_all == target:
            self.res.append(self.path[:])
            return
        # 進行回溯
        for i in range(start_index, len(candidates)):
            # 終止條件
            if sum_all + candidates[i] > target:
                break
            # 去重操作
            if i > start_index and candidates[i] == candidates[i-1]:
                continue

            sum_all += candidates[i]
            self.path.append(candidates[i])
            self.backtracing(candidates, target, sum_all, i+1)
            sum_all -= candidates[i]
            self.path.pop()

    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        self.res.clear()
        self.path.clear()
        # 先進行排序
        candidates.sort()
        self.backtracing(candidates, target, 0, 0)
        return self.res
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末谷徙,一起剝皮案震驚了整個濱河市拒啰,隨后出現(xiàn)的幾起案子驯绎,更是在濱河造成了極大的恐慌完慧,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異屈尼,居然都是意外死亡册着,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門脾歧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甲捏,“玉大人,你說我怎么就攤上這事鞭执∷径伲” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵兄纺,是天一觀的道長大溜。 經(jīng)常有香客問我,道長估脆,這世上最難降的妖魔是什么钦奋? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮疙赠,結果婚禮上付材,老公的妹妹穿的比我還像新娘。我一直安慰自己圃阳,他們只是感情好厌衔,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捍岳,像睡著了一般葵诈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上祟同,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天作喘,我揣著相機與錄音,去河邊找鬼晕城。 笑死泞坦,一個胖子當著我的面吹牛,可吹牛的內容都是我干的砖顷。 我是一名探鬼主播贰锁,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼滤蝠!你這毒婦竟也來了豌熄?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤物咳,失蹤者是張志新(化名)和其女友劉穎锣险,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡芯肤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年巷折,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片崖咨。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡锻拘,死狀恐怖,靈堂內的尸體忽然破棺而出击蹲,到底是詐尸還是另有隱情署拟,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布歌豺,位于F島的核電站芯丧,受9級特大地震影響,放射性物質發(fā)生泄漏世曾。R本人自食惡果不足惜缨恒,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望轮听。 院中可真熱鬧骗露,春花似錦、人聲如沸血巍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽述寡。三九已至柿隙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鲫凶,已是汗流浹背禀崖。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留螟炫,地道東北人波附。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像昼钻,于是被迫代替她去往敵國和親掸屡。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內容