用 Swift 來刷 leet code 吧

2021-02-21 iOS大全

為什麼要用 Swift 刷 leetcode?因為我有兩個想法,一是學 Swift 並且有機會練練,二是想把 leetcode 刷完。於是,這兩個想法就合二為一了,現在我以基本一天一道的速度在刷。

首先 Swift 這門語言效率不高,有些算法拿別的語言過得去,拿 Swift 就會超時(雖然是跟 case 有關係,不過 Swift 效率確實不高)。其次,Swift 有很多麻煩的地方,尤其是字符串處理上。它甚至都不能隨機訪問字符串裡某個位置的字符……還得先轉成一個字符數組,也就意味著凡是有字符串的題的時間和空間複雜度都不會小於 O(n) 了。還有一些字符串相關的 API 會影響效率,如果想讓代碼簡潔就會超時…… 總之感覺如果是練習算法,不用考慮這些因素是最好的,從這個角度來說,Swift 並不是最適合刷 leet code 的語言。但當然也是可行的,如果你有興趣,一起來刷吧。

Two Sum (Easy) 題解

很簡單的 hash。一個小技巧是,對於每個數先看和為 target 所需的數是否已經在 dict 裡,如果已經在則直接返回,否則才把自身放進 dict 裡。這樣只需循環一次,不用先構建 hash、再遍歷,循環兩次。

時間複雜度:O(n) 空間複雜度:O(n)

Add Two Numbers (Medium) 題解

簡單的單鍊表處理。考慮幾種情況:1. 兩個數位數相等,且最高位不需進位 2. 兩個數位數相等,且最高位需要進位 3. 兩個數位數不相等。

有些人寫的時候會在結果的頭部先創建一個dummy,val任意,真正的頭結點直接往dummy後面插。最後返回dummy -> next。

時間複雜度:O(n) 空間複雜度:O(1)

Longest Substring Without Repeating Characters (Medium) 題解

我用的方法是用一個 hash 記錄每個字母出現的index,然後把字符串掃一遍。不出現重複時就往 hash 表裡填。出現重複時,從 hash 取出字母出現的 previousIndex,把從當前串開頭至previousIndex的字母都從 hash 中清掉。

看到一個更好的方法,不需要存字母出現的index,出現重複時直接從當前串開頭至出現重複字母的位置清掉 hash 即可。這種情況下也不需要用Dictionary存 hash,只需用Set即可。

本來 hash 需要的額外空間很小,但因為 swift 要遍歷字符串中的字符必須把字符數組存出來一份。所以空間複雜度為 O(n)。

時間複雜度:O(n) 空間複雜度:O(n)

Median of Two Sorted Arrays (Hard) 題解

下面列出了兩個解法,其中 Solution2 是自己想出來的,也過了全部測試數據,但方法非常不簡潔。思路是從兩邊逼近中位數,取兩個數列的中點,可證明總有一個不能滿足第 k 大的條件。然後就調整這個數列。問題在於,有些情況可能會調整過頭。另外,還有這個數列已經到頭、調整不了的情況,此時就需要去調另一個數列。總的來說仍然是 log(m + n) 的,但代碼非常長,原理也不夠清晰。

Solution1 參考了別人的題解,每次兩個數列各取 k/2 處,小者在這個位置之前全都截斷。

為啥 Solution1 就非常簡潔呢?最主要的問題在於,Solution1 是從一側逼近問題的,每次迭代都更靠近答案。Solution2 是從兩側往中間逼近,然而兩個數列並沒有二分查找那麼好的特性,有可能兩個指針都在答案的同側,還要回頭找。

另外,Solution1 利用了一個技巧,保證每次迭代時 nums1 都更短,不然交換。可以避免很多對稱的重複代碼。

在語言方面,可以看出 swift 裡if(...) {return ...}這種基本都用guard代替。

時間複雜度:log(m+n) 空間複雜度:O(m+n)

Longest palindromic Substring (Medium) 題解

這個解法是 O(n^2) 的。DP,先搜長度為 1、為 2…… 至 n。之所以寫法很不簡潔,多出了許多臨時變量,完全是 swift 的鍋。謹記 swift 字符串的特性,由於每一位字符長度不一定相等,它是不能隨機訪問的。也就是說,如果不存臨時變量,取某一位的字符、取字符串的長度、截取子串,全部都是 n 級別的…… 所以一再超時。

感覺很坑的是,我之前寫作isPalidromeMatrix[startIndex][endIndex] = ...這樣就會超時,而if (...) {isPalidromeMatrix[startIndex][endIndex] = true}這樣就不會。只不過多賦值了一些 false……

而且把if isPalidrome改成if isPalidromeMatrix[startIndex][endIndex],時間會長一倍。感覺數據量稍微一大,swift 性能問題真的挺嚴重。

時間複雜度:O(n^2) 空間複雜度:O(n^2)

這個題是有一個 O(n) 的算法的。首先有暴搜的思路,就是以任何一位為中心往外擴展。O(n) 的算法是在這個基礎上,利用回文串的特性,存在一個子串那麼中心點兩側對稱,在此基礎上再往外搜即可。具體可見這篇文章

ZigZag Conversion (Easy) 題解

非常簡單的題,唯一的難點就是題目本身描述得不太清楚了。需要自己考慮 row = 1、2 的邊界情況。

swift 有個stride函數用來處理 for step 的情況。

時間複雜度:O(n) 空間複雜度:O(n)

Reverse Integer (Easy) 題解

這題本身很簡單,但感覺是道不錯的面試題。可以測試面試者是否考慮各種邊界情況,對溢出有沒有概念。

測試用例對 swift 給的不對,只能用Int32.max。我是把負數統一歸成正數來計算,這樣判斷溢出的語句可以簡單點。

時間複雜度:O(lgn) 空間複雜度:O(1)

String to Integer (Easy) 題解

這道題與其說是寫代碼不如說是寫 case…… 一堆 case,真是一點懶都不能偷呀。

時間複雜度:O(n) 空間複雜度:O(n)

Palindrome Number (Easy) 題解

很簡單的題,沒給出的條件是負數不算迴文數。有個 case 1000021 一開始做錯了。另外一開始寫了個遞歸,後來發現沒必要……

時間複雜度:O(n) 空間複雜度:O(1)

Regular Expression Matching (Hard) 題解

評級為 hard,但感覺這題不難…… 就是遞歸一位一位往後讀,遇到 * 就分兩種情況,用盡這個 token 或者下輪接著用這個 token。

一個問題就是直接遞歸會超時。需要先把正則式處理一下:

aa 合併為 a*

a.b 合併為 .(就是 . 前後所有的 x 全都去掉)。

時間複雜度:O(n) 空間複雜度:O(n)

Container With Most Water (Medium) 題解

本來想的是搜索加剪枝,搜以每個點做一端的。最壞情況 O(n^2),結果最後有兩組數據(就是最壞情況)過不去,超時。

改成題解裡這樣,從兩邊往中間搜,結果變成 O(n) 了。想改成記憶化搜索,發現很難。

搜索的順序果然還是非常重要!很多東西從後往前搜,從中間往兩邊搜,從兩邊往中間搜,就差得多了……

時間複雜度:O(n) 空間複雜度:O(1)

Integer to Roman (Medium) 題解

很簡單的遞歸,沒什麼可說的。就是細心一點吧。

看到有的題解是把 1000、900、500 都存起來,這樣確實快很多,因為不用考慮往左加的情況。另外非遞歸因為不用算 10 次冪可能略快一點。

時間複雜度:O(lgn) 空間複雜度:O(1)

Roman to Integer (Easy) 題解

很簡單的題,沒啥可說的。分情況討論,簡單遞歸即可(我怎麼這麼喜歡遞歸……)

看到一個題解的思路挺巧妙,倒著往前掃,比前一位大就往上加,沒前一位大就減掉。算是利用了羅馬數字一個很好的特性吧。

不過想了想好像沒啥倒過來的必要啊…… 直接從前往後掃也是一樣 O O

時間複雜度:O(n) 空間複雜度:O(n)

Longest Common Prefix (Easy) 題解

最簡單的字符串處理,沒什麼可說的。

時間複雜度:O(nm) 空間複雜度:O(nm)

3Sum (Medium) 題解

我用的還是 hash 方法,先找第一個數、再找第二個數…… 去重的方法就是要求三個數的序關係,這樣就不會重了。

看到一個題解用的是先排序,然後先定第一個數,第二個數左頭,第三個數右頭。然後大了挪小的、小了挪大的…… 這樣。算是另一種思路吧。

時間複雜度:O(n^2) 空間複雜度:O(n)

3Sum Closest (Medium) 題解

這時候就用上上一題的排序思路了。先排好序,然後指定第一個數從左往右,第二個為第一個數右邊(剩下區間的最左端),第三個數為最右端。然後小了把左邊的往右挪、大了把右邊的往左挪……

時間複雜度:O(n^2) 空間複雜度:O(n)

Letter Combinations of a Phone Number (Medium) 題解

懶癌犯了…… 明明一道廣搜的題,又寫成「遞歸」了,僅僅是因為懶得開兩個數組…… 是不是已經沒得救了 O O

好吧,後面老實補了一個正常版本。然後發現「遞歸」版本快得多…… 完全想不到任何原因呀,明明「遞歸」版本無謂地構造了一些後綴字符串,難道是拷貝數組很慢?

時間複雜度:O(3^n) 空間複雜度:O(3^n)

4Sum (Medium) 題解

在 3Sum 基礎上的延伸,先排序,再循環前兩位,後兩位左右夾逼。聽說這樣會超時?然而並沒有,時間還在中位數左右。500多ms

一些簡單的剪枝,比如夾逼時最小的兩個數都不夠小、最大的兩個數都不夠大,那也就沒必要繼續了。加了這些剪枝,雖然代碼長了很多很多,但是嗖快嗖快的,只要 52 ms。一下 beats 100% submissions,好有成就感呀。

時間複雜度:O(n^3) 空間複雜度:O(n)

Remove Nth Node From End of List (Easy) 題解

挺簡單的題,沒什麼可說的。只要兩個指針,第一個指向頭部,第二個指向第 n 個節點;然後把兩個指針同時往後挪,當第二個指針到尾部時,第一個指針指向的就是就是倒數第 n 個節點,把它去了就行了。

時間複雜度:O(n) 空間複雜度:O(n)

Valid Parentheses (Easy) 題解

大概是棧的最簡單的一道題了。如果是左括號,push;是右括號,pop,如果不匹配返回 false。結束後如果棧空則返回 true,否則返回 false。

時間複雜度:O(n) 空間複雜度:O(n)

相關焦點

  • ​LeetCode刷題實戰139:單詞拆分
    算法的重要性,我就不多說了吧,想去大廠,就必須要經過基礎知識和業務邏輯面試+算法面試。
  • 從Java到Swift
    6.nil在swift中就類似Java中的null。nil是沒有初始化成功,是沒有值。7.optional value是指該value的值可以是nil,Swift默認一個var是不能賦值nil,除非它聲明了optional。optional不能直接輸出,而必須unwrap,形如optionalValue!。有點類似於Java中打包好的null判斷。也可以用!代替?
  • Swift教程(一)--基礎內容
    元組允許你創建和傳遞一組的數據,你可以用元組當做函數的返回值來返回多個的值Swift還增加了可選項,用來處理沒有值的情況,它使得Swift更安全,這也充分說明swift是一門類型安全的程式語言,那麼現在讓我們開始swift的編程之旅吧常量和變量顧名思義,常量的值一旦設置好便不能再被更改,然而變量的值可以在將來被設置成不同的值
  • Swift 語言學習及速查手冊
    究其原因,大概是如下幾個原因吧:恐懼未知。對未知的東西沒有把握,怕太難,怕需要太長時間學,所以能拖就拖。注意力不能集中。連續玩幾個小時遊戲一點不累,看半小時書就感覺身心俱疲。番茄工作法在這個時候就起作用了,告訴自己,不想太多,開始一個番茄鍾試試,在這 25 分鐘內,只關注這 25 分鐘內要看的內容。然後,很自然的,障礙被逐個擊破,番茄鍾一個接著一個。
  • 希望用一種規律搞定背包問題
    示例 1:輸入: s = "leetcode", wordDict = ["leet", "code"]輸出: true解釋: 返回 true 因為 "leetcode" 可以被拆分成 "leet code"。
  • Swift中編寫單例的正確方式
    先劇透一下吧:總共有4個版本。我們來清點一下:1.This enables a cool way to use `dispatch_once` in your code: just declare a global variable with an initializer and mark it private.」)
  • 「小心」新詐騙電話 只要Zip Code就刷爆你信用卡
    時下身分盜竊新的騙術就只等你給出家庭住地區號(Zip code),轉眼間刷爆你的信用卡。最近聖蓋博華人聚居地區不少民眾收到情況類似的詐騙電話,與幾年來濫用的「中國領事館找你」、「國稅局要查你帳」、「海關發現你的郵包有問題」等詐騙手法不同,這次騙子們似乎掌握更多個人信息,然後使用「核對」套路設下圈套,如果不提高警覺
  • 來一次有側重點的區分Swift與Objective-C
    一、Objective-C與Swift的異同1.1、swift和OC的共同點:1.2、swift的優點:- swift注重安全,OC注重靈活- swift注重面向協議編程、函數式編程、面向對象編程,OC注重面向對象編程- swift注重值類型,OC注重指針和引用- swift是靜態類型語言,OC是動態類型語言- swift容易閱讀,文件結構和大部分語法簡易化,只有.swift文件,結尾不需要分號- swift中的可選類型,是用於所有數據類型,而不僅僅局限於類。
  • 《 Swift 程式語言》中文版教程開源
    https://github.com/SwiftGGTeam/the-swift-programming-language-in-chinese項目使用GitBook製作的,可以在線閱讀,原文和翻譯版網址如下。
  • 零基礎學習Swift中的數據科學
    有一些有用的庫,比如CoreML,可以讓我們用Python來訓練大型模型,並直接將它們導入到Swift中進行推理。此外,它還提供了大量的預先訓練過的先進模型,我們可以直接使用它們來構建iOS/macOS應用程式。
  • swift語言是什麼?蘋果最新編程swift語言資料
    swift語言是什麼?蘋果最新編程swift語言資料 2014-06-05 11:28 | 作者:SORA | 來源:265G QQ群號:624022706 |
  • 簡單介紹 Swift on Fedora ——在 Fedora 中使用 Swift
    支持方法,擴展和協議的結構函數式編程模式,例如映射和過濾(map and filter)內置強大的錯誤處理功能使用 do,guard,defer 和 repeat 關鍵字編寫高級控制流程在 Fedora 中試用 Swift現已支持在 Fedora 28 中使用 Swift,不過需要安裝名為 swift-lang
  • Debian中編寫你的第一個Apple Swift程序
    在Debian 10上安裝Swift編譯器所有Swift版本都可以通過以下網頁找到:https://swift.org/download/#releases在這裡,我們將介紹Swift版本5.0.1的安裝,一切通過命令行來操作。
  • RxSwift 實戰教程-核心用法
    override func viewDidLoad() {        super.viewDidLoad()    }}另外建立一個RegisterViewModel.swift文件,一個Protocol.swift文件,一個Service.swift文件我們先寫那個比較好呢?
  • Swift、國際清算系統和數字貨幣
    因為現在在崗位上做國際結算和清算業務的朋友,大多數上手做這項業務時就是用swift的,因此在他們眼裡,做國際結算和清算,就是通過swift做的。清算系統是一套銀行的帳戶體系以及相互間資金劃撥交割的會計規則。資金進行清算,需要有效的憑證和指令作為依據,也就是業務信息。這些信息的傳遞方式,可以是指定的,也可以是各自選擇的。
  • iOS面試題-Swift篇
    class 有以下功能,struct 是沒有的:*class可以繼承,子類可以使用父類的特性和方法類型轉換可以在運行時檢查和解釋一個實例對象class可以用 deinit來釋放資源一個類可以被多次引用結構較小,適用於複製操作,相比較一個class 實例被多次引用,struct 更安全無需擔心內存洩露問題Swift 中
  • 通過LLVM 在 Android 上運行 Swift 代碼
    假設是可以的,我們來看看如何實現。手動構建 Swift 代碼如果使用 Xcode,系統會自動完成這些。我們現在需要手動編譯和連接一個簡單的 Swift "Hello world" :// hello.swiftprint("Hello, world!")
  • 化妝刷用久了會爛臉?來學學怎麼洗化妝刷吧!
    今天小茂就向大家安利一下化妝刷清潔利器吧。DAISO大創粉撲清洗劑雖然叫粉撲清洗劑,但是清洗任何化妝工具都不是問題。這款清洗劑是化妝工具清洗劑的入門級選手,便宜大碗,怎麼用都不心疼,重點是還洗得很乾淨。只需在化妝刷刷頭,或者粉撲上加上適量的清洗劑搓洗,就可以輕鬆洗掉所有殘留啦。