1. 程式人生 > >Leetcode 940:不同的子序列 II(最詳細的解法!!!)

Leetcode 940:不同的子序列 II(最詳細的解法!!!)

給定一個字串 S,計算 S 的不同非空子序列的個數。

因為結果可能很大,所以返回答案模 10^9 + 7.

示例 1:

輸入:"abc"
輸出:7
解釋:7 個不同的子序列分別是 "a", "b", "c", "ab", "ac", "bc", 以及 "abc"。

示例 2:

輸入:"aba"
輸出:6
解釋:6 個不同的子序列分別是 "a", "b", "ab", "ba", "aa" 以及 "aba"。

示例 3:

輸入:"aaa"
輸出:3
解釋:3 個不同的子序列分別是 "a", "aa" 以及 "aaa"。

提示:

  1. S 只包含小寫字母。
  2. 1 <= S.length <= 2000

解題思路

我們首先想到的思路是暴力破解,通過控制抽取S中元素個個數,得到不同的組合,最後計算所有組合的總數。

from itertools import combinations
class Solution:
    def distinctSubseqII(self, S):
        """
        :type S: str
        :rtype: int
        """
        S, result = list(S), list()
        count = 0
        count +=
len(set(S)) if len(S) >= 2: for i in range(2,len(S)+1): result.append(set(combinations(S, i))) for i in result: for _ in i: count += 1 return count%(10**9 + 7)

但是很明顯這種做法不可取,太慢了。我們以這個思路為起點,如果我們想要計算S的所有不同子序列個數,我們只需要知道除去最後一個元素的s[:-2]

所有不同子序列個數k,那麼我們最後的結果就是2k-以s[-1]結尾的所有子序列。現在我們的問題就變成了,怎麼計算以s[-1]結尾的所有子序列?如果我們當前要考慮的元素,如S[-1],和之前的所有元素都不同,那麼之前必然不會有以s[-1]結尾的所有子序列。如果之前出現過當前考慮的元素的話,那麼以s[-1]結尾的所有子序列的個數就是最近一次以s[-1]結尾的所有子序列。例如

a a a
    |

此時,我們知道我們之前的序列有aaa" "。現在我們要將a加上,也就是我們會有2*3=6個子序列,但是之前序列中以a結尾的序列有兩個,所以我們的最後結果就是6-2=4。但是因為我們最後不考慮" ",所以還要減去1

class Solution:
    def distinctSubseqII(self, S):
        """
        :type S: str
        :rtype: int
        """
        pos, mod, cur_sum = [0]*26, 1e9+7, 1
        for c in S:
            old_sum = cur_sum
            cur_sum = (cur_sum*2 - pos[ord(c) - 97]) % mod
            pos[ord(c) - 97] = old_sum
        return cur_sum - 1

還可以這樣去思考,我們遍歷輸入的S,例如

a b a
|

此時,我們碰到的以a結尾的字串只有a。然後

a b a
  |

此時,以b結尾的字串有abb,也就是a+b" "+b(上一次的結果加上b)。(這其實就是trie

a b a
    |

此時,以a結尾的字串有ababaaaa,也就是ab+ab+aa+a" "+a(上一次的結果加上a)。所以我們最後的結果就是以ab結尾的字串個數總和。

實現上,我們需要建立一個26大小的陣列以容納不同字母結尾的字串個數。每當我們遍歷到一個新的字母時,此時我們只要將陣列中所有結果加起來然後再加1即為以新的字母為結尾的字串總數。最後我們只要將陣列中的結果加起來即可。

class Solution:
    def distinctSubseqII(self, S):
        """
        :type S: str
        :rtype: int
        """
        end = [0] * 26
        for c in S:
            end[ord(c) - 97] = sum(end) + 1
        return sum(end) % (10**9 + 7)

reference:

https://leetcode.com/problems/distinct-subsequences-ii/discuss/192017/C++JavaPython-4-lines-O(N)-Time-O(1)-Space

https://www.geeksforgeeks.org/count-distinct-subsequences/

我將該問題的其他語言版本新增到了我的GitHub Leetcode

如有問題,希望大家指出!!!