【每日一題】LeetCode. 面試題16.18. 模式匹配

每日一題,防止癡呆 = =

一、題目大意

你有兩個字符串,即pattern和value。 pattern字符串由字母"a"和"b"組成,用於描述字符串中的模式。例如,字符串"catcatgocatgo"匹配模式"aabab"(其中"cat"是"a",“go"是"b”),該字符串也匹配像"a"、"ab"和"b"這樣的模式。但需注意"a"和"b"不能同時表示相同的字符串。編寫一個方法判斷value字符串是否匹配pattern字符串。
在這裏插入圖片描述
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/pattern-matching-lcci

二、題目思路以及AC代碼

思路

一開始我以爲會是DP的題,想設dp[i][j]表示pattern前i個字符和value前j個字符是否匹配來着,後來發現好像並沒有遞推關係 = =。

其實這道題說起來就是一個枚舉的題目,但是直接在源字符串上找匹配並不好處理,我們可以枚舉pattern中a和b可能表示的字符串長度。我們設a表示的字符串長度爲len_a,b表示的字符串長度爲len_b,a在pattern中的個數爲count_a,b在pattern中的個數爲count_b,那麼如果模式匹配的話,則一定滿足:

len_a * count_a + len_b * count_b = v_size
其中v_size是value字符串的長度。這樣的話,我們只需要對 len_a 進行枚舉,就可以計算出len_b,從而去遍歷檢查是否是模式匹配的。

當然這道題還有許多邊界情況。

  • len_a 和 len_b 一定都是大於等於0的
  • 如果value是空,那麼pattern只有爲空,或者pattern中只包含一種字符時,纔會匹配
  • 如果pattern爲空,那麼只有value爲空纔會匹配
  • 如果value和pattern都是非空的,那麼我們就要對pattern中出現的那個字符進行枚舉(如果都出現可以枚舉任意一個)。

這樣的話,我們可以預先把 a 和 b 設定好角色,也就是讓其中一個總是pattern中出現次數較多的那個元素,這樣我們就可以將上述一些邊界情況簡化了。

AC代碼
class Solution {
public:
    bool patternMatching(string pattern, string value) {
    	// 用來記錄pattern中出現a和b的次數
        int count_a = 0, count_b = 0;

		// 統計pattern中的a和b
        for (char ch: pattern) {
            if (ch == 'a') count_a++;
            else count_b++;
        }
		
		// 保證a始終是pattern中出現次數較多的那個
		// 這樣並不會影響結果
        if (count_a < count_b) {
            swap(count_a, count_b);
            for (char& ch: pattern) {
                if (ch == 'a') ch = 'b';
                else ch = 'a';
            }
        }

		// 如果value是空,要麼pattern是空,要麼pattern中只有一種元素
		// 由於上面保證a是出現次數較多的了,這裏count_b == 0就包含了上述兩種情況
        if (value.empty()) return count_b == 0;
        // 如果value非空,pattern爲空,那麼直接返回false
        if (pattern.empty()) return false;

		// 下面就是針對len_a進行遍歷
        int v_size = value.size();
        for (int len_a = 0;len_a * count_a <= v_size;len_a++) {
            int rest = v_size - len_a * count_a;
			// 如果count_b是0,那麼rest也得是0,不然無法匹配
			// 如果count_b不是0,那麼rest必須可以整除count_b,計算b的長度
            if ((count_b == 0 && rest == 0) || (count_b && rest % count_b == 0)) {
                string value_a, value_b;
                int pos = 0;
                bool correct = true;
                for (char ch: pattern) {
                    if (ch == 'a') {
                        string temp = value.substr(pos, len_a);
                        if (value_a.empty()) value_a = temp;
                        else if (value_a != temp) {
                            correct = false;
                            break;
                        }
                        pos += len_a;
                    }
                    else {
                        string temp = value.substr(pos, rest / count_b);
                        if (value_b.empty()) value_b = temp;
                        else if (value_b != temp) {
                            correct = false;
                            break;
                        }
                        pos += rest / count_b;
                    }
                }
                // 這裏我覺得可能測試數據有些不全
                // 我一開始是忘了加value_a != value_b的,但是也通過了
                // 不過按照題目要求,結果的a和b是不能表示相同的字符串的
                // 可以試一下 value = "dogdogdogdogdog", pattern = "abbba"
                if (correct && value_a != value_b) return true;
            }
        }

        return false;
    }
};

如果有問題,歡迎大家指正!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章