Swift 演算法實戰之路(一)

發表於2016-05-24
Swift 演算法實戰之路(一)

Swift是蘋果新推出的程式語言,也是蘋果首個開源語言。相比於原來的Objective-C,Swift要更輕便和靈活。筆者最近使用Swift實踐了大量的演算法(絕大部分是矽谷各大公司的面試題),將心得體會總結於下。此文並不是純粹討論Swift如何實現某一個具體的演算法或者資料結構,如氣泡排序、深度優先遍歷,或是樹和棧,而是總結歸納一些Swift常用的語法和技巧,以便大家在解決面試題中使用。

基本語法

先來看下面一段程式碼

上面程式碼實現了一個非常簡單的功能,就是交換一個陣列中的兩個值。乍一看非常正確,實際上存在以下幾個問題。

  1. 在第一個引數前應該加上 inout 關鍵字。因為在Swift中,struct都是按值傳遞,class是按引用傳遞;陣列和字典都是struct。所以要改變原來的chars陣列,在其前部加入inout關鍵字,表示是按引用傳遞。
  2. p 和 q 之前應該加入下劃線。Swift預設函式的第一個引數是區域性(local)變數,而後續引數都是外部(external)變數,外部變數必須宣告。如果在p和q前加上下劃線,則在呼叫函式時無需宣告外部變數,這樣呼叫起來更簡便。
  3. temp前的var應該改為let。let用於宣告常量(constant),var用於宣告變數(variable)。swap函式中,temp並未進行修改,所以應當視為常量,用let來宣告。

修改過後的程式碼為

再來看一段程式碼

這裡在 x -= 1 處會報錯。原因是函式中所有的引數是常量(let),是不可以修改的。解決的方法是在函式中寫上var x = x,之後就可以對 x 進行修改了

迴圈

Swift迴圈分為for和while兩種,注意他們的結構跟傳統的 Java, C/C++有很大區別,筆者將其總結如下

以上程式碼非常簡單。需要說明的有兩個,一個是 for _ in 0 .. 。當我們不需要陣列中每一個具體的元素值時,我們就可以用下劃線來代表序號。
另一個是是 repeat { } while i 。這個相當於我們熟悉(java)的 do { } while (i 。

排序

swift排序效率很高,寫法也很簡潔。筆者將其總結如下

活用Guard語句

使用Guard語句可以讓邏輯變得非常清楚,尤其是在處理演算法問題的時候,請看下面的程式碼

上面這段程式碼是求字串needle在字串haystack裡首次出現的位置。我們發現for迴圈中的巢狀非常繁瑣,但是如果使用Guard語句程式碼會變得清晰很多:

Guard語句的好處是判斷條件永遠是我們希望的條件而不是特殊情況,且成功避免了大量的if巢狀。

另外在上面程式碼中,為何要將字串轉化成陣列進行處理?因為Swift中沒有方法能夠以O(1)的時間複雜度取得字串中的字元,我們常用的string.startIndex.advancedBy(n)方法,其時間複雜度為O(n)。所以筆者在這裡以空間換時間的方法進行了優化。

總結

Swift是一門獨特的語言,本文對其基本知識和語法進行了適當歸納,文中提到的都是基本細節。下期我們會討論更加進階的內容。

相關文章