算法題:消除字符串中全部的b和連續的ac


最近碰到了一道面試題,雖然不難但是臨試沒想出好的解法,記錄下來以作分享。

題目:消除字符串中全部的b和連續的ac

用例:

  • 'aabbc' -> 'a'
  • 'aaabbbccc' -> ''
  • 'abcdcba' -> 'dca'

注意結合用例理解這個題目的意思,轉化后的字符串中不能有任何b和連續的ac,而不是僅對初始值進行一次轉換。

暴力法

既然最后得到的字符串中不能有任何b和連續的ac,那么我們可以很容易地想到使用正則連續地進行處理,直到處理前后的字符串相同,可以很容易地寫出下面的代碼:

function solution (str) {
  const reg = /ac|b/g
  let strCopy = str
  do {
    str = strCopy
    strCopy = str.replace(reg, '')
  } while (strCopy !== str)
  return strCopy
}

但是暴力法顯然不夠好,它每次重復地去執行替換,對於aaaaaccccc這種字符串,需要執行5次。

那么有沒有更好的方法呢?通過觀察我們發現其實需要替換的字符序列必定符合{n個a}{m個b}{n個c}(m, n不都為0)這種格式。b我們可以先不去管它,先從格式開頭的a入手。那么如果找到了a,怎么知道后面的字符序列中有沒有c出現呢?而c出現的個數是否能跟a的個數匹配呢?我們可以先保存連續a的數量,然后如果后面出現了符合格式的c,則減少a的個數,直到a耗盡或者格式匹配失敗。

存儲a的解法

function solution(str) {
    let countA = 0  // 連續a的個數
    let result = ''
    for (let i = 0; i < str.length; i++) {
        if (str[i] === 'a') {
            countA++
        } else if (str[i] === 'b') {
            continue
        } else if (str[i] === 'c') {
            if (countA === 0) {
                result += 'c'
            } else {
                countA--
            }
        } else {
            // 遇到其他字符,則保存的a需要釋放
            while (countA) {
                result += 'a'
                countA--
            }
            result += str[i]
        }
    }
    // 最后需要釋放所有保存的a
    while (countA) {
        result += 'a'
        countA--
    }
    return result
}

存儲a的解法有點類似於棧,遇到a入棧,遇到c出棧,遇到abc之外的字符排空棧。

這是一種時間復雜度O(n)的解法,但是在遇到類似aaaaaad這種字符串的時候,它還不夠好,因為最后保存的a都要釋放出來,有額外的時間開銷。

雙指針的解法

這是本題較好的一種解法,設兩個指針cur和loc分別從頭開始出發,cur每次移動一格,另一個指針loc保留當前的操作位置,如果cur指向的字符是c且loc指向的是a,則將loc回移一位(ac抵消了),如果遇到其他非b的字符,則將loc處的字符置為cur處的字符,一直進行直到到cur到達字符串尾部,此時取字符串開頭到loc指針之間的子串即為本題的解。這種解法妙就妙在loc處的字符是即時更新的,一些邊界條件都自動消除了。

畫一個圖更好理解一點,比如有字符串abeabcdaabbcg,它經過處理后應該得到aedag,下面是操作過程的圖解:

這種方法在C++, Java中是可以實現in-place更新的,但Javascript字符串是不可變的,所以體現不出來。

function solution(str) {
    let result = str.split('')
    let location = -1
    for (let i = 0; i < str.length; i++) {
        let cur = str[i]
        if (cur === 'c' && location >= 0 && result[location] === 'a') {
            location --
        } else if (cur !== 'b') {
            result[++location] = cur
        }
    }
    return result.slice(0, location + 1).join('')
}

最后做個技術總結,這道題難度不大,考察的是對字符串算法的理解,雙指針、棧、動態規划等思想在字符串算法問題中還是有很多應用的,還是要通過學習去總結歸納。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM