Leetcode【78滥朱、90根暑、289、621徙邻、718】

問題描述:【BFS排嫌、Bit】78. Subsets
解題思路:

方法1(回溯法):

這道題是給一個數(shù)組,返回所有的子集缰犁。

首先可以想到用回溯法 BFS 求解淳地,如 nums = [0,2,5]怖糊,使用回溯法可以依次得到 [0]、[0,2]薇芝、[0,2,5]蓬抄、[0,5]、[2]夯到、[2,5]、[5]

注意:(1)把空集 [] 也加進去饮亏;(2)集合的子集是組合數(shù)耍贾,因此可以把 nums 的索引也當(dāng)作參數(shù)傳入,防止出現(xiàn)排列數(shù)路幸。

Python3 實現(xiàn):

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        def search(d, ind, path):  # d為深度荐开,ind保證組合數(shù),path保存結(jié)果
            for i in range(ind, N):
                path.append(nums[i])
                ans.append(path[:])  # 防止傳引用調(diào)用
                if d < N:
                    search(d+1, i+1, path)
                path.pop()  # 回溯一步
                
        ans = [[]]
        N = len(nums)
        search(1, 0, [])
        return ans

方法2(位操作):

因為長度為 len(nums) 的子集有 2^len(nums) 個简肴,由此可以想到每一個子集對應(yīng)一個 len(nums) 位的二進制數(shù)晃听。如果二進制數(shù)某一位為 '1',那么就代表該位置有 nums[i]砰识。如 nums = [0,2,5]能扒,len(nums) = 3,有 2^3 = 8 個子集辫狼,那么二進制數(shù) 000初斑、001、010膨处、011见秤、100、101真椿、110鹃答、111 分別對應(yīng) []、[5]突硝、[2]测摔、[2,5]、[0]狞换、[0,5]避咆、[0,2]、[0,2,5]修噪。

Python3 實現(xiàn):

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        N = len(nums)
        ans = []
        for i in range(1 << len(nums)):
            bin_s = bin(i)[2:].zfill(N)  # 前面補0到長度N
            path = []
            for i in range(len(bin_s)):
                if bin_s[i] == '1':  # 如果某位為'1'
                    path.append(nums[i])
            ans.append(path)
        return ans

問題描述:【BFS查库、Bit】90. Subsets II
解題思路:

這道題是給一個數(shù)組,數(shù)組中的數(shù)字可能有重復(fù)黄琼,返回所有可能的子集樊销。

相比于上面的 Leetcode 78整慎,這道題只是數(shù)字可能有重復(fù)而已,我們同樣可以使用回溯法 BFS 和位操作 Bit 來求解围苫。

先把結(jié)果保存在集合中裤园,這樣如果后面有重復(fù)的項,判斷是否在集合中的時間復(fù)雜度為 O(1)剂府。還要注意拧揽,要先對 nums 進行排序。為什么呢腺占?

比如 nums = [2,1,2]淤袜,無論采取 BFS 還是 Bit 方法,會出現(xiàn) [2,1] 和 [1,2] 兩種情況衰伯,集合視它們是不同的铡羡。但是如果先排序,nums = [1,2,2]意鲸,只會有 [1,2] 這種情況出現(xiàn)烦周,因此先要對 nums 進行排序。

最后還要注意一點:因為 list 是不可哈希的類型(unhashable type)怎顾,如果進行諸如 list in set 的判斷會出錯读慎。可以將每次的結(jié)果轉(zhuǎn)化為 tuple杆勇,因為 tuple 是可以哈希的贪壳,因此就不會報錯。

除此之外蚜退,求解過程和 Leetcode 78 幾乎相同闰靴。

Python3 實現(xiàn)(BFS):

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        def search(d, ind, path):
            for i in range(ind, N):
                path.append(nums[i])
                if tuple(path) not in ans:
                    ans.add(tuple(path))  # 將結(jié)果轉(zhuǎn)化為可哈希的tuple再存入集合中
                if d < N:
                    search(d+1, i+1, path)
                path.pop()
        
        N = len(nums)
        nums.sort()  # 先對nums排序,因為有重復(fù)的數(shù)字
        ans = set()
        ans.add(tuple([]))
        search(1, 0, [])
        return list(ans)

Python3 實現(xiàn)(Bit):

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        N = len(nums)
        nums.sort()  # 先對nums排序钻注,因為有重復(fù)的數(shù)字
        ans = []
        for i in range(1 << len(nums)):
            bin_s = bin(i)[2:].zfill(N)
            path = []
            for i in range(len(bin_s)):
                if bin_s[i] == '1':
                    path.append(nums[i])
            if tuple(path) not in ans:
                ans.append(tuple(path))  # 將結(jié)果轉(zhuǎn)化為可哈希的tuple再存入集合中
        return list(ans)

問題描述:【Array】289. Game of Life
解題思路:

這道題是給一個 01 矩陣蚂且,每個位置看成一個細胞。1 為活細胞幅恋,0 為死細胞杏死。每個細胞與其八個相鄰位置(水平,垂直捆交,對角線)的細胞遵循四條生存定律淑翼,求根據(jù)當(dāng)前 01 矩陣狀態(tài)計算下一個 01 矩陣狀態(tài)。

這道題需要注意的有兩點:(1)所有細胞改變改變是同時發(fā)生的品追;(2)要在原矩陣上修改玄括,不能創(chuàng)建額外的空間。

第一點好辦肉瓦,對于每個位置的活細胞或死細胞遭京,統(tǒng)計周圍八個位置的活細胞的數(shù)量胃惜,按照生存定律改變狀態(tài)。

但是考慮到第二點哪雕,只能在原數(shù)組上修改狀態(tài)船殉,如果 1 修改成 0 或者 0 改成 1,就會影響后面的細胞的判斷斯嚎。所以就不能將 1 先改成 0利虫,也不能將 0 先改成 1。我們可以先把 1 改成 -1堡僻,后面的細胞每次判斷加一個 abs列吼,-1 的絕對值還是 1,就不影響苦始;而對于 0 而言,因為不可能改成 -0慌申,所以先隨便改一個陌选,如 float("inf")(反正不是 1 和 -1 就行,不然影響后面判斷)蹄溉。等所有的細胞狀態(tài)改完之后咨油,再遍歷一遍矩陣,把所有的 -1 改成 0柒爵,把所有的 float("inf") 改成 1 即可役电。

Python3 實現(xiàn):
class Solution:
    def gameOfLife(self, board: List[List[int]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        pos = [[-1,0], [1,0], [0,-1], [0,1], [-1,-1], [-1,1], [1,-1], [1,1]]  # 周圍8個位置
        m = len(board)
        n = len(board[0])
        for i in range(m):
            for j in range(n):
                live = 0  # 活細胞的數(shù)量
                if board[i][j] == 0:
                    for p in pos:
                         if 0 <= i+p[0] < m and 0 <= j+p[1] < n and abs(board[i+p[0]][j+p[1]]) == 1:
                            live += 1
                    if live == 3:
                        board[i][j] = float("inf")  # 先把0改成float("inf")
                elif board[i][j] == 1:
                    for p in pos:
                        if 0 <= i+p[0] < m and 0 <= j+p[1] < n and abs(board[i+p[0]][j+p[1]]) == 1:
                            live += 1
                    if live < 2 or live > 3:
                        board[i][j] = -1  # 先把1改成-1
        for i in range(m):  # 把所有float("inf")改成1,把所有-1改成0
            for j in range(n):
                if board[i][j] == float("inf"):
                    board[i][j] = 1
                elif board[i][j] == -1:
                    board[i][j] = 0

問題描述:【Greedy】621. Task Scheduler
解題思路:

這道題是模擬 CPU 任務(wù)分配棉胀,給一個數(shù)組 tasks 存儲 A 到 Z法瑟,表示不同的任務(wù),任務(wù)可以以不同順序進行唁奢。每個任務(wù)可以在一個時間間隔中完成霎挟。對于一個時間間隔,CPU 可以執(zhí)行一個任務(wù)或者是閑置麻掸。但是酥夭,兩個同樣的任務(wù)之間至少需要有 n 個冷卻時間,也就是說假如 A 執(zhí)行后脊奋,那么未來 n 個時間間隔內(nèi)熬北,A 是不允許再執(zhí)行的。

這道題我剛開始的想法也是用貪婪算法求解诚隙。

  • 先對 tasks 按任務(wù)出現(xiàn)的次數(shù)從大到小排序讶隐。假設(shè)有 k 個任務(wù)都是出現(xiàn)了最多的次數(shù),為 x 次最楷,那么時間至少為 ans = (x-1)*(n+1)+k整份。如 task = ['A','A','A','B','B','B']待错,如果 n=2,那么 ans = 2*3+2 = 8烈评,即這樣安排 "AB(idle)AB(idle)AB"火俄。
  • 對于次數(shù)小于 x 的任務(wù),假設(shè)為 C讲冠,可以發(fā)現(xiàn)瓜客,如果有空閑單元,這樣的插入也是滿足要求的竿开。如 task = ['A','A','A','B','B','B','C', 'D']谱仪,如果 n=2,那么 ans = 2*3+2 = 8否彩,即這樣安排 "ABCABDAB"疯攒。
  • 但是,如果任務(wù)多的話列荔,有些任務(wù)就插不進去了敬尺,如 task = ['A','A','A','B','B','B','C','D','E'],如果 n=2贴浙,那么按照公式 ans = 8砂吞,但實際上 'E' 無法插進去,答案應(yīng)該是 9崎溃。因此蜻直,卡到了這一步,沒有思路嚶嚶嚶...

實際上袁串,再想一下概而,答案就出來了。即我們可以在原來的基礎(chǔ)上這樣插 "ABC(E)ABDAB"般婆,可以發(fā)現(xiàn)到腥,按照公式計算出來的 ans = 8 小于數(shù)組長度(9),我們直接返回數(shù)組長度即可蔚袍。再舉一個例子乡范,tasks = ['A','A','A','B','B','B','C', 'C', 'D', 'D', 'E'],可以這樣插 "ABCDEABCDAB"啤咽,ans = 8 < len(tasks) = 11晋辆,直接返回數(shù)組長度 11 即可。

這是一種貪心的策略宇整,即 A 一定能夠符合距離下一個 A 的冷卻時間為 n瓶佳,那么跟在 A 后面的也一定符合。只要保證 A 符合就行了鳞青,其他任務(wù)的的符合要求都可以由 A 的符合推導(dǎo)出來霸饲。

時間復(fù)雜度為 O(N)为朋,即統(tǒng)計各個任務(wù)次數(shù)的花銷;空間復(fù)雜度為 O(26)厚脉,保存最多 26 個任務(wù)出現(xiàn)的次數(shù)。

Python3 實現(xiàn):
class Solution:
    def leastInterval(self, tasks: List[str], n: int) -> int:
        dic = collections.Counter(tasks)
        x = max(dic.values())  # 出現(xiàn)最多次數(shù)
        k = 0  # 出現(xiàn)最多次數(shù)的任務(wù)有幾個
        for v in dic.values():
            if v == x:
                k += 1
        return max((n+1)*(x-1)+k, len(tasks))  # 按照公式算出來的值可能比tasks長度小

問題描述:【DP】718. Maximum Length of Repeated Subarray
解題思路:

這道題是給兩個數(shù)組傻工,求最長公共子數(shù)組。

同最長公共字串問題 逞炱ィ考的經(jīng)典算法--最長公共子序列(LCS)與最長公共子串(DP),用動態(tài)規(guī)劃求解即可泄伪。

Python3 實現(xiàn):
class Solution:
    def findLength(self, A: List[int], B: List[int]) -> int:
        dp = [[0] * (len(B) + 1) for _ in range(len(A) + 1)]
        max_ = 0
        for i in range(1, len(A) + 1):
            for j in range(1, len(B) + 1):
                if A[i-1] == B[j-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                    max_ = max(max_, dp[i][j])
        return max_
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末殴蓬,一起剝皮案震驚了整個濱河市蟋滴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脓杉,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件简逮,死亡現(xiàn)場離奇詭異球散,居然都是意外死亡散庶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門屋讶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來须教,“玉大人,你說我怎么就攤上這事轻腺。” “怎么了挤土?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵误算,是天一觀的道長迷殿。 經(jīng)常有香客問我咖杂,道長,這世上最難降的妖魔是什么止邮? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任奏窑,我火速辦了婚禮,結(jié)果婚禮上撩匕,老公的妹妹穿的比我還像新娘墨叛。我一直安慰自己,他們只是感情好漠趁,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布闯传。 她就那樣靜靜地躺著,像睡著了一般甥绿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洗出,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天图谷,我揣著相機與錄音,去河邊找鬼隅茎。 笑死嫉沽,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的堂竟。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼席楚,長吁一口氣:“原來是場噩夢啊……” “哼税稼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起郎仆,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤扰肌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后曙旭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年爷绘,在試婚紗的時候發(fā)現(xiàn)自己被綠了进倍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片购对。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖骡苞,靈堂內(nèi)的尸體忽然破棺而出解幽,到底是詐尸還是另有隱情,我是刑警寧澤躲株,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布霜定,位于F島的核電站廊鸥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辖所。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一吆视、第九天 我趴在偏房一處隱蔽的房頂上張望酥宴。 院中可真熱鬧,春花似錦丰滑、人聲如沸倒庵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寻仗。三九已至,卻和暖如春极阅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背筋搏。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工奔脐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人峦朗。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓排龄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子闭翩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 專業(yè)考題類型管理運行工作負責(zé)人一般作業(yè)考題內(nèi)容選項A選項B選項C選項D選項E選項F正確答案 變電單選GYSZ本規(guī)程...
    小白兔去釣魚閱讀 8,981評論 0 13
  • 1.埋點是做什么的 2.如何進行埋點 3.埋點方案的設(shè)計 近期常被問到這個問題疗韵,我擔(dān)心我的答案會將一些天真爛漫的孩...
    lxg閱讀 2,012評論 0 1
  • 1. 關(guān)于診斷X線機準(zhǔn)直器的作用蕉汪,錯誤的是()逞怨。 (6.0 分) A. 顯示照射野 B. 顯示中心線 C. 屏蔽多...
    我們村我最帥閱讀 10,344評論 0 5
  • 問題描述:【Two Pointers】524. Longest Word in Dictionary throug...
    牛奶芝麻閱讀 523評論 0 0
  • 動態(tài)規(guī)劃 111. 爬樓梯思路類似斐波那契數(shù)列注意考慮第 0 階的特殊情況 272. 爬樓梯 II思路類似上題胖秒,只...
    6默默Welsh閱讀 2,418評論 0 1