1. 程式人生 > 其它 >leetcode-38:外觀數列

leetcode-38:外觀數列

技術標籤:演算法python正則表示式pythonleetcode演算法

LC 外觀數列

題目:

題目連結

給定一個正整數 n ,輸出外觀數列的第 n 項。
「外觀數列」是一個整數序列,從數字 1 開始,序列中的每一項都是對前一項的描述。
你可以將其視作是由遞迴公式定義的數字字串序列:

  • countAndSay(1) = "1"
  • countAndSay(n) 是對 countAndSay(n-1) 的描述,然後轉換成另一個數字字串。

前五項如下:

1.     1
2.
11 3. 21 4. 1211 5. 111221 第一項是數字 1 描述前一項,這個數是 1 即 “ 一 個 1 ”,記作 "11" 描述前一項,這個數是 11 即 “ 二 個 1 ” ,記作 "21" 描述前一項,這個數是 21 即 “ 一 個 2 + 一 個 1 ” ,記作 "1211" 描述前一項,這個數是 1211 即 “ 一 個 1 + 一 個 2 + 二 個 1 ” ,記作 "111221"

要 描述 一個數字字串,首先要將字串分割為 最小 數量的組,每個組都由連續的最多 相同字元 組成。然後對於每個組,先描述字元的數量,然後描述字元,形成一個描述組。要將描述轉換為數字字串,先將每組中的字元數量用數字替換,再將所有描述組連線起來。

例如,數字字串 “3322251” 的描述如下圖:
在這裡插入圖片描述
示例 1:

輸入:n = 1
輸出:"1"
解釋:這是一個基本樣例。

示例 2:

輸入:n = 4
輸出:"1211"
解釋:
countAndSay(1) = "1"
countAndSay(2) ="1" = 一 個 1 = "11"
countAndSay(3) ="11" = 二 個 1 = "21"
countAndSay(4) ="21" = 一 個 2
+ 一 個 1 = "12" + "11" = "1211"

解題

方法一:遞迴

def countAndSay(self, n: int) -> str:
    if n == 1:
        return '1'
    s = self.countAndSay(n-1)
    
    i, res = 0, ''
    for j, c in enumerate(s):
        if c != s[i]:
            res += str(j-i) + s[i]
            i = j
    res += str(len(s) - i) + s[-1]  # 最後一個元素莫忘統計
    return res

方法二:迭代

def countAndSay(self, n: int) -> str:
    res = '1'
    for _ in range(n-1):  # 控制迴圈次數
        i, tmp = 0, ''
        for j, c in enumerate(res):
            if c != res[i]:
                tmp += str(j-i) + res[i]
                i = j
        res = tmp + str(len(res) - i) + res[-1]
    return res

方法三:正則表示式:提取元素

def countAndSay(self, n: int) -> str:
    if n == 1:
        return '1'
    s = self.countAndSay(n-1)

    p = r'(\d)\1*'
    pattern = re.compile(p)
    res = [_.group() for _ in pattern.finditer(s)]  # 提取結果
    return ''.join(str(len(c)) + c[0] for c in res)  # join 內部的 str(len(c)) + c[0] for c in res 是生成器型別

字串 (\d)\1* 可以用來匹配結果。這裡用來提取連在一塊的元素, 如 '111221',提取出的元素是 res = ['111', '22', '1']。
然後再返回我們要組裝的字串。

方法四:正則表示式:元素替換

def countAndSay(self, n: int) -> str:
    res = '1'
    p = r'(\d)\1*'
    pattern = re.compile(p)
    for _ in range(n-1):
        res = pattern.sub(lambda x: str(len(x.group())) + x.group(1), res)  # 替換
    return res

對於該句:res = pattern.sub(lambda x: str(len(x.group())) + x.group(1), res),還是拿上面的舉例,對於 111221 的第一個匹配項 111,其中 group() 匹配的是 111(全域性匹配),而 group(1) 匹配到的是 1 (第一個捕獲組,三個 1 中的第一個)。