Swift算法實戰(zhàn):翻轉字符串

字符串在算法中經(jīng)常遇到,下面以兩道題目為例,學習如何進行字符串的翻轉疗隶。

一、我們來一起看一道以前的Google面試題翼闹。

Given an input string, reverse the string word by word.
A word is defined as a sequence of non-space characters.
The input string does not contain leading or trailing spaces and the words are always separated by a single space.
For example,
Given s = "the sky is blue",
return "blue is sky the".
Could you do it in-place without allocating extra space?

看到這道題的時候斑鼻,先整理下思路,解題步驟分為兩步如下:

  1. 將整個字符串翻轉猎荠,即遍歷前后每個字符進行互換:
    the sky is blue --> eulb si yks eht
  2. 逐個單詞進行翻轉坚弱, 遍歷字符串根據(jù)“ ”空格字符獲取單詞,然后對每個單詞進行翻轉:
    eulb si yks eht --> blue is sky the

答題之前关摇,我們先用 Tuple實現(xiàn)一個通用的字符串翻轉的方法:

fileprivate func swap<T>(_ chars: inout [T], _ p: Int, _ q: Int) {
    (chars[p], chars[q]) = (chars[q], chars[p])
}

如果你正在使用swift 4.0荒叶,那實現(xiàn)起來更加簡單

Swift 4.0 新增特性: String 又變成了集合類型
新增函數(shù) reversed,實現(xiàn)字符串翻轉输虱。
下面是官方示例:

let word = "Backwards"
for char in word.reversed() {
    print(char, terminator: "")
}
// Prints "sdrawkcaB"

let reversedWord = String(word.reversed());
print("\n" + reversedWord)
// Prints "sdrawkcaB"

開始解題:

func reverseWords(s: String?) -> String? {
    guard s != nil else {
        return nil
    }
    
    var chars = Array(s!.characters), start = 0
    _reverse(&chars, 0, chars.count - 1)
    
    for i in 0 ..< chars.count {
        if i == chars.count - 1 || chars[i + 1] == " " {
            _reverse(&chars, start, i)
            start = i + 2
        }
    }
    return String(chars)
}

fileprivate func _reverse<T>(_ chars: inout [T], _ start: Int, _ end:Int){
    var start = start, end = end
    while start < end {
        swap(&chars,start,end)
        start += 1
        end -= 1
    }
}

時間復雜度還是O(n)些楣,整體思路和代碼簡單很多。

  • 但在 Swift 4.0 環(huán)境下宪睹,你會發(fā)現(xiàn)string.character這個方法在3.2的時候已經(jīng)被遺棄愁茁,那結合上文提到的特性,重新實現(xiàn)了一下:
func reverseWords(s: String?) -> String? {
    guard s != nil else {
        return nil
    }

    //翻轉整體字符串
    let chars4 = String(s!.reversed())
    print(chars4)
    
    var startIdx = s?.startIndex, endIdex = s?.endIndex
    var result = String()

    //逐個單詞進行翻轉横堡,然后拼接
    while let comma = chars4[startIdx!..<endIdex!].index(of: " ") {
        
        result.append(String(chars4[startIdx!..<comma].reversed()) + " ")
        startIdx = chars4.index(after: comma)
    }
    result.append(String(chars4[startIdx!..<endIdex!].reversed()))
    print(result)
    
    return String(result)
}
二埋市、如果將上面的題目 "the sky is blue" 改成返回結果是:"is blue the sky" 那需要怎么做呢?
解題三步反轉法:

對于這個問題命贴,換一個角度思考一下道宅。

將一個字符串分成X和Y兩個部分,在每部分字符串上定義反轉操作胸蛛,先將X的所有字符串翻轉污茵,再翻轉Y的所有字符串,最后翻轉整個字符串就實現(xiàn)了整個翻轉葬项。

按照下述3個步驟操作即可:

  1. 首先將字符串分成兩個部分泞当,
    即X:"the sky",Y:"is blue"
  2. 先將X進行翻轉:the sky-->yks eht民珍,
    再講Y進行翻轉:is blue-->eulb si
  3. 翻轉上述步驟得到的結果字符串襟士,即翻轉字符串 "yks eht eulb si" 的兩部分(yks eht和eulb si)給予反轉盗飒,"yks eht eulb si" 得到 "is blue the sky",這就實現(xiàn)了整個反轉陋桂。
    如下圖所示:


    reversed.png

    代碼實現(xiàn)如下:

func leftRotateString(str: String?, n: Int, m: Int) ->String? {
    var  m = m, n = n
    m %= n    //若要左移動大于n位逆趣,那么和%n 是等價的
    
    var chars = Array(str!.characters)
    print(String(chars))

    //_reverse 引用之前第一題的寫好的函數(shù)
    _reverse(&chars, 0, m - 1)//翻轉X,即:the sky-->yks eht
    _reverse(&chars, m + 1, n - 1)//翻轉Y嗜历,即:is blue-->eulb si(注意處理空字符宣渗,m+1)
    _reverse(&chars, 0, n - 1)//整體翻轉,即:yks eht eulb si-->is blue the sky
    
    return String(chars)
}

這就是把字符串分為兩個部分梨州,先各自反轉再整體反轉的方法痕囱,時間復雜度為O(n),空間復雜度為O(1)暴匠,達到了題目的要求鞍恢。

參考資料:
http://www.reibang.com/p/977736b08bd7
https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/01.01.md

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市巷查,隨后出現(xiàn)的幾起案子有序,更是在濱河造成了極大的恐慌抹腿,老刑警劉巖岛请,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異警绩,居然都是意外死亡崇败,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進店門肩祥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來后室,“玉大人,你說我怎么就攤上這事混狠“杜” “怎么了?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵将饺,是天一觀的道長贡避。 經(jīng)常有香客問我,道長予弧,這世上最難降的妖魔是什么刮吧? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮掖蛤,結果婚禮上杀捻,老公的妹妹穿的比我還像新娘。我一直安慰自己蚓庭,他們只是感情好致讥,可當我...
    茶點故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布仅仆。 她就那樣靜靜地躺著,像睡著了一般垢袱。 火紅的嫁衣襯著肌膚如雪蝇恶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天惶桐,我揣著相機與錄音撮弧,去河邊找鬼。 笑死姚糊,一個胖子當著我的面吹牛贿衍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播救恨,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼贸辈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肠槽?” 一聲冷哼從身側響起擎淤,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎秸仙,沒想到半個月后嘴拢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡寂纪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年席吴,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捞蛋。...
    茶點故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡孝冒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拟杉,到底是詐尸還是另有隱情庄涡,我是刑警寧澤,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布搬设,位于F島的核電站穴店,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏焕梅。R本人自食惡果不足惜迹鹅,卻給世界環(huán)境...
    茶點故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贞言。 院中可真熱鬧斜棚,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至义钉,卻和暖如春昧绣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捶闸。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工夜畴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人删壮。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓贪绘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親央碟。 傳聞我的和親對象是個殘疾皇子税灌,可洞房花燭夜當晚...
    茶點故事閱讀 45,585評論 2 359

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