算法作業系列10——Unique Substrings in Wraparound String

算法作業系列(十)

Unique Substrings in Wraparound String

寫在前面

如果你是因爲沒有思路來找答案的,這裏建議你去看看題目的s,因爲s是一個連續字母的字符串,所以,在這裏s並不是一個具體的字符串,而是一個限制條件而已,因此,希望沒有思考的你再去看看題目,因爲動態規劃的問題,其實寫多了也就是那麼回事,想通了就好,其實是有套路的,而且個人認爲套路比貪心還要簡單。所以,這種套路學會了,一些簡單層次的動態規劃問題就很簡單了。

題目

Consider the string s to be the infinite wraparound string of “abcdefghijklmnopqrstuvwxyz”, so s will look like this: “…zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd….”.

Now we have another string p. Your job is to find out how many unique non-empty substrings of p are present in s. In particular, your input is the string p and you need to output the number of different non-empty substrings of p in the string s.

Note: p consists of only lowercase English letters and the size of p might be over 10000.

Example 1:
Input: "a"
Output: 1
Explanation: Only the substring "a" of string "a" is in the string s.
Example 2:
Input: "cac"
Output: 2
Explanation: There are two substrings "a", "c" of string "cac" in the string s.
Example 3:
Input: "zab"
Output: 6
Explanation: There are six substrings "z", "a", "b", "za", "ab", "zab" of string "zab" in the string s.

思路

既然是在動態規劃這一類裏面,我們就從動態規劃的角度去思考問題,其實動態規劃也就是把一個大的問題拆分成一個小一點的問題,伴隨而來的一般就是一個可以解決的問題,也就是說,動態規劃的問題可以將現有問題分成一些小一點的問題和一個邏輯上可以直接解決出來的問題。而最重要的就是把公式推導出來,比如這一題,我以一個數組f代表每個位置會添加多少個新的子串,那就很好知道,如果當前的字符是上一個字符的下一個字母,那麼當前的這個字符的加入,就可能會使得整體的子串的數目加上f(n - 1)個,那如果不連續呢,就爲0,這裏舉個例子來看:
zabd是給出的字符串,那麼第一個字符爲z,肯定沒辦法帶來新的收益(這裏帶來的收益指的是新增加的子串的數目,長度至少爲2);
而對於a,由於z和a是連續的,所以a的加入會帶來收益,那具體多少的收益呢?我們看上一個字符z,收益爲0,也就意味着z這裏跟前面是不連續的,那麼a的加入就只會帶來za一個收益,我們記錄下來爲2;
再看b,發現和a是連續的,那麼說明它也有可能帶來收益,那帶來多少呢?我們看前一個字母a,由於這裏的a帶來的收益爲1,那就說明a這裏最長的連續子串長度爲2,那對於b,帶來的收益就有ab、zab這兩個;
最後看d,發現不連續,既然我們考慮的只有長度爲2及以上的字符串,那麼我們就記爲0,因爲沒法帶來收益。

經過上面的流程,我覺得大家應該很容易把狀態轉移方程寫出來了:
f(i) = f(i - 1) + 1(連續) f(i) = 0(不連續),第一個字母的值爲0最。後的結果就是出現的字母的數目加上每一個f裏面的值的和。

那我們接下來解釋一下爲什麼說可能帶來收益,我們看這麼一個字符串abdab,我們看這裏的b,就會有一個情況,就是前面的b爲1,後面的b也爲1,但是這裏都是ab的字符串,所以就重複了,那怎麼解決呢?答案就是,對於每一個字母,只去帶來最多收益的那個。

好,那我們只需要每次記錄下當前字母的值,再和以前的最大值比較,看看誰更大就要誰就好了。

參考代碼

class Solution {
public:
    int findSubstringInWraproundString(string p) {
        if (p.length() == 0) {
            return 0;
        }
        int* num = new int[p.length()];
        map<char, int> cnt;
        num[0] = 0;
        cnt[p[0]] = 0;
        for (int i = 1; i < p.length(); i++) {
            cnt[p[i]] = cnt[p[i]];
            if (p[i] == p[i - 1] + 1 || (p[i - 1] == 'z' && p[i] == 'a')) {
                num[i] = num[i -1] + 1;
                if (cnt[p[i]] < num[i]) {
                    cnt[p[i]] = num[i];
                }
            } else {
                num[i] = 0;
            }
        }

        int total = cnt.size();
        for (map<char, int>::iterator i = cnt.begin(); i != cnt.end(); i++) {
            total += i->second;
        }
        return total;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章