Python小白 Leetcode刷題歷程 No.71-No.75 簡化路徑、編輯距離、矩陣置零、搜索二維矩陣、顏色分類 (有題干 有代碼 有思路心得)

Python小白 Leetcode刷題歷程 No.71-No.75 簡化路徑、編輯距離、矩陣置零、搜索二維矩陣、顏色分類

寫在前面:

作為一個計算機院的大學生,總覺得僅僅在學校粗略的學習計算機專業課是不夠的,尤其是假期大量的空檔期,作為一個小白,實習也莫得路子,又不想白白耗費時間。于是選擇了Leetcode這個平臺來刷題庫。編程我只學過基礎的C語言,現在在自學Python,所以用Python3.8刷題庫。現在我Python掌握的還不是很熟練,算法什么的也還沒學,就先不考慮算法上的優化了,單純以解題為目的,復雜程度什么的以后有時間再優化。計劃順序五個題寫一篇日志,希望其他初學編程的人起到一些幫助,寫算是對自己學習歷程的一個見證了吧。

有一起刷LeetCode的可以關注我一下,我會一直發LeetCode題庫Python3解法的,也可以一起探討。

覺得有用的話可以點贊關注下哦,謝謝大家!
········································································································································································

No.71.簡化路徑

難度:中等
題目描述:


在這里插入圖片描述

在這里插入圖片描述

題解代碼(Python3.8)

class Solution:
    def simplifyPath(self, path: str) -> str:
        stack=[]
        path=path.split('/')
        for item in path:
            if item == '..':
                if stack:
                    stack.pop()
            elif item and item!='.':
                stack.append(item)
        return '/'+'/'.join(stack)

或許有用的知識點:
這道題可能用到split()函數,split()函數的一些介紹如下:

在這里插入圖片描述

在這里插入圖片描述

解題思路:
這道題有關路徑,可以運用棧的思想。先初始化一下,將原字符串在有”/”的地方分割開,形成一系列小字符串,再將小字符串依次壓入棧中,碰到”..”就將棧中最后一個元素彈出,碰到”.”不做修改。最后將棧中元素按照目錄的格式依次輸出形成字符串即可。

No.72.編輯距離

難度:困難
題目描述:


在這里插入圖片描述

題解代碼(Python3.8)

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        l1 = len(word1)
        l2 = len(word2)
        dp = [[0]*(l2+1) for _ in range(l1+1)]
        for j in range(1,l2+1):                     #第一行
            dp[0][j] = dp[0][j-1] + 1   
        for i in range(1,l1+1):                     #第一列
            dp[i][0] = dp[i-1][0] + 1
        for i in range(1,l1+1):
            for j in range(1,l2+1):
                if word1[i-1] == word2[j-1]:        #word[i]對應dp[i+1]        
                    dp[i][j] = dp[i-1][j-1]
                else:                               #進行‘增’,‘刪’,‘改’
                #(dp[i-1][j]+1)為‘增’,(dp[i][j-1]+1)為‘刪’,(dp[i-1][j-1]+1)為‘改’
                    dp[i][j] = min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1
        return dp[l1][l2]

或許有用的知識點:
這道題要用到動態規劃,且有動態規劃問題中‘自底向上’思路和‘自頂向下’思路區別的分析(‘自頂向下’的思路可能要用到‘緩存+遞歸’的方法,此時會用到functools.lru_cache裝飾器,再本題’優解代碼及分析中有詳細介紹‘)。
‘自底向上’的思路是比較容易想到的,是先依次解決小問題,最終解決所求問題;在樹形結構中,就是先解決底部的問題,再一層層解決向上的問題,最后解決頂部的所求問題。
而‘自頂向下’的思路是比較不容易想到的,是先看解決最終問題依次需要解決哪些小問題,再解決所有的小問題;在樹形結構中,就是先看解決頂部的問題需要解決哪些子問題,再看解決這些子問題需要解決哪些子問題,直到解決最底部的問題。引用知乎大佬給出的生動形象的小例子:
某日小明上數學課,他的老師給了很多個不同的直角三角板讓小明用尺子去量三角板的三個邊,并將長度記錄下來。兩個小時過去,小明完成任務,把數據拿給老師。老師給他說,還有一個任務就是觀察三條邊之間的數量關系。又是兩個小時,聰明的小明連蹦帶跳走進了辦公室,說:“老師,我找到了,三條邊之中有兩條,它們的平方和約等于另外一條的平方。”老師拍拍小明的頭,“你今天學會了一個定理,勾股定理。它就是說直角三角形有兩邊平方和等于第三邊的平方和”。
另一個故事,某日老師告訴小明“今天要教你一個定理,勾股定理。”小明說,“什么是勾股定理呢?”“勾股定理是說,直角三角形中有兩條邊的平方和等于第三邊的平方。”然后老師給了一大堆直角三角板給小明,讓他去驗證。兩個小時后,小明告訴老師定理是正確的.
兩個故事剛好是語法分析里面對應的兩個方法:第一個故事說的是自底向上的分析方法,第二個故事說的是自頂而下的分析方法。

解題思路:
這道題是求最優解的問題,我們可以使用動態規劃的方法。套用動態規劃算法的模板,對于這道題,令dp[i][j]為代表word1到i位置轉換成word2到j位置需要最少步數,則動態規劃的三要素為:
狀態:
對“dp[i-1][j-1] 表示替換操作,dp[i-1][j] 表示刪除操作,dp[i][j-1] 表示插入操作。”的理解:以 word1 為 "horse",word2 為 "ros",且 dp[5][3] 為例,即要將 word1的前 5 個字符轉換為 word2的前 3 個字符,也就是將 horse 轉換為 ros,因此有:
(1) dp[i-1][j-1],即先將 word1 的前 4 個字符 hors 轉換為 word2 的前 2 個字符 ro,然后將第五個字符 word1[4](因為下標基數以 0 開始) 由 e 替換為 s(即替換為 word2 的第三個字符,word2[2])。
(2) dp[i][j-1],即先將 word1 的前 5 個字符 horse 轉換為 word2 的前 2 個字符 ro,然后在末尾補充一個 s,即插入操作。
(3) dp[i-1][j],即先將 word1 的前 4 個字符 hors 轉換為 word2 的前 3 個字符 ros,然后刪除 word1 的第 5 個字符。
狀態轉移方程:
if word1[i-1] == word2[j-1]: dp[i][j] = dp[i-1][j-1]
else: dp[i][j] = min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1
邊界條件:
for j in range(1,l2+1): dp[0][j] = dp[0][j-1] + 1
for i in range(1,l1+1): dp[i][0] = dp[i-1][0] + 1

優解代碼及分析:
優解代碼(Python3.8)

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        import functools
        @functools.lru_cache(None)
        def helper(i, j):
            if i == len(word1) or j == len(word2):
                return len(word1) - i + len(word2) - j
            if word1[i] == word2[j]:
                return helper(i + 1, j + 1)
            else:
                inserted = helper(i, j + 1)
                deleted = helper(i + 1, j)
                replaced = helper(i + 1, j + 1)
                return min(inserted, deleted, replaced) + 1
        return helper(0, 0)

分析:
這其實是緩存+遞歸的方式,原理和動態規劃一樣。要用到functools.lru_cache裝飾器。


在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

No.73.矩陣置零

難度:中等
題目描述:


在這里插入圖片描述

題解代碼(Python3.8)

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        l_row = len(matrix)
        l_col = len(matrix[0])
        flag_row0 = False
        flag_col0 = False
        for j in range(l_col):       #判斷第一行是否有0
            if matrix[0][j] == 0:
                flag_row0 = True
                break
        for i in range(l_row):        #判斷第一列是否有0
            if matrix[i][0] == 0:
                flag_col0 = True
                break
        for i in range(l_row):      #以第一行、第一列列作為標志位,記錄0的存在與否
            for j in range(l_col):
                if matrix[i][j] == 0:
                    matrix[i][0] = matrix[0][j] = 0
        for i in range(1,l_row):      #置0過程(除邊界)
            for j in range(1,l_col):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0
        if flag_row0:               #第一行置0
            for j in range(l_col):
                matrix[0][j] = 0
        if flag_col0:               #第一列置0
            for i in range(l_row):  
                matrix[i][0] = 0

解題思路:
用matrix第一行和第一列記錄該行該列是否有0,作為標志位。但是對于第一行,和第一列要設置一個標志位,為了防止自己這一行(一列)也有0的情況.注釋寫在代碼里,直接看代碼很好理解!

優解代碼及分析:
優解代碼(Python3.8)

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        flag_col = False
        l_row = len(matrix)
        l_col = len(matrix[0])
        for i in range(l_row):
            if matrix[i][0] == 0: 
                flag_col = True
            for j in range(1,l_col):
                if matrix[i][j] == 0:
                    matrix[i][0] = matrix[0][j] = 0
        for i in range(l_row - 1, -1, -1):
            for j in range(l_col - 1, 0, -1):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0
            if flag_col == True: 
                matrix[i][0] = 0

分析:
這是之前題解的簡化版,用循環減少了一個空間復雜度。

No.74.搜索二維矩陣

難度:中等
題目描述:


在這里插入圖片描述

題解代碼(Python3.8)

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        if (not matrix) or (not matrix[0]):
            return False
        m=len(matrix)
        n=len(matrix[0])
        left=0
        right=m*n-1
        while left<=right:
            mid=(left+right)//2
            if matrix[mid//n][mid%n] == target:
                return True
            elif matrix[mid//n][mid%n] > target:
                right=mid-1
            else:
                left=mid+1
        return False

或許有用的知識點:
這道題要用到二分查找算法。

解題思路:
首先將二維數組投影為一維數組,如下圖所示。
算法流程:
1.特判,若matrix為空或matrix[0]為空,主要應對[]和[[]]。
2.初始化矩陣行數m和列數n。初試化查詢左右界l=0,r=m*n-1。
3.循環條件,當l<=r時進入循環:mid=(l+r)//2,若matrix[mid//n][mid%n]==target,直接返回True;如果matrix[mid//n][mid%n]>target,令r=mid-1;否則,令l=mid+1返回False。

No.75.顏色分類

難度:中等
題目描述:


在這里插入圖片描述

題解代碼(Python3.8)

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        l = len(nums)
        if l < 2:
            return
        zero = 0
        two = l
        i = 0
        # all in [0, zero) = 0
        # all in [zero, i) = 1
        # all in [two, len - 1] = 2
        while i < two:
            if nums[i] == 0:
                nums[i],nums[zero] = nums[zero],nums[i]
                i += 1
                zero += 1
            elif nums[i] == 1:
                i += 1
            else:
                two -= 1
                nums[i],nums[two] = nums[two],nums[i]

或許有用的知識點:
這道題要用到雙指針的思想。
做對這道題需要熟悉快速排序的 partition 過程,重點是設置循環不變量(在Java的JDK源碼中Arrays.sort()有同種方法,如下圖)。

在這里插入圖片描述

解題思路:
循環不變量是這樣定義的:
所有在子區間 [0, zero) 的元素都等于 0;所有在子區間 [zero, i) 的元素都等于 1;所有在子區間 [two, len - 1] 的元素都等于 2。這滿足了設計循環不變量的原則——“不重不漏”。
1、len 是數組的長度;2、變量 zero 是前兩個子區間的分界點,一個是閉區間,另一個就必須是開區間;3、變量 i 是循環變量,一般設置為開區間,表示 i 之前的元素是遍歷過的;4、two 是另一個分界線,我設計成閉區間。
編碼的時候,zero 和 two 初始化的值就應該保證上面的三個子區間全為空。在遍歷的過程中,“索引先加減再交換”、還是“先交換再加減”就看初始化的時候變量在哪里。退出循環的條件也看上面定義的循環不變量,在 i == two 成立的時候,上面的三個子區間就正好“不重不漏”地覆蓋了整個數組,并且給出的性質成立,題目的任務也就完成了。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容