LeetCode #936 Stamping The Sequence 戳印序列 936 Stamping The Sequence 戳印序列

936 Stamping The Sequence 戳印序列

Description:
You are given two strings stamp and target. Initially, there is a string s of length target.length with all s[i] == '?'.

In one turn, you can place stamp over s and replace every letter in the s with the corresponding letter from stamp.

For example, if stamp = "abc" and target = "abcba", then s is "?????" initially. In one turn you can:
place stamp at index 0 of s to obtain "abc??",
place stamp at index 1 of s to obtain "?abc?", or
place stamp at index 2 of s to obtain "??abc".
Note that stamp must be fully contained in the boundaries of s in order to stamp (i.e., you cannot place stamp at index 3 of s).
We want to convert s to target using at most 10 * target.length turns.

Return an array of the index of the left-most letter being stamped at each turn. If we cannot obtain target from s within 10 * target.length turns, return an empty array.

Example:

Example 1:

Input: stamp = "abc", target = "ababc"
Output: [0,2]
Explanation: Initially s = "?????".

  • Place stamp at index 0 to get "abc??".
  • Place stamp at index 2 to get "ababc".
    [1,0,2] would also be accepted as an answer, as well as some other answers.

Example 2:

Input: stamp = "abca", target = "aabcaca"
Output: [3,0,1]
Explanation: Initially s = "???????".

  • Place stamp at index 3 to get "???abca".
  • Place stamp at index 0 to get "abcabca".
  • Place stamp at index 1 to get "aabcaca".

Constraints:

1 <= stamp.length <= target.length <= 1000
stamp and target consist of lowercase English letters.

題目描述:
你想要用小寫字母組成一個目標字符串 target。

開始的時候,序列由 target.length 個 '?' 記號組成。而你有一個小寫字母印章 stamp。

在每個回合,你可以將印章放在序列上,並將序列中的每個字母替換爲印章上的相應字母。你最多可以進行 10 * target.length 個回合。

舉個例子,如果初始序列爲 "?????",而你的印章 stamp 是 "abc",那麼在第一回合,你可以得到 "abc??"、"?abc?"、"??abc"。(請注意,印章必須完全包含在序列的邊界內才能蓋下去。)

如果可以印出序列,那麼返回一個數組,該數組由每個回合中被印下的最左邊字母的索引組成。如果不能印出序列,就返回一個空數組。

例如,如果序列是 "ababc",印章是 "abc",那麼我們就可以返回與操作 "?????" -> "abc??" -> "ababc" 相對應的答案 [0, 2];

另外,如果可以印出序列,那麼需要保證可以在 10 * target.length 個回合內完成。任何超過此數字的答案將不被接受。

示例 :

示例 1:

輸入:stamp = "abc", target = "ababc"
輸出:[0,2]
([1,0,2] 以及其他一些可能的結果也將作爲答案被接受)

示例 2:

輸入:stamp = "abca", target = "aabcaca"
輸出:[3,0,1]

提示:

1 <= stamp.length <= target.length <= 1000
stamp 和 target 只包含小寫字母。

思路:

逆向模擬
因爲題意正向模擬會覆蓋之前的字符, 難以記錄, 可以將 target 與 stamp 對應位置相同的字符用 "?" 代替, 最後如果全是 "?" 說明可以替換成功
每次從一個位置開始以 stamp 的大小作爲一個窗口遍歷 target, 並將 target 對應位置上的字符修改爲 "?", 直到沒有修改 target 退出循環
如果能夠修改成功, 將當前位置加入結果列表
最後如果 target 全部字符被修改爲 "?" 說明可以修改, 返回結果的逆序, 因爲加入時是逆序
否則返回空數組
時間複雜度爲 O(n ^ 2), 空間複雜度爲 O(n ^ 2), n 爲 target 長度, m 爲 stamp 長度, n >= m, 時間複雜度爲 O(n(n - m))

代碼:
C++:

class Solution 
{
public:
    vector<int> movesToStamp(string stamp, string target) 
    {
        int m = stamp.size(), n = target.size(), count = 0;
        vector<int> result, empty_list;
        bool change = true;
        while (change)
        {
            change = false;
            for (int i = 0; i < n - m + 1; i++) change |= check(i, m, stamp, target, result);
        }
        for (const auto& c : target) if (c == '?') ++count;
        reverse(result.begin(), result.end());
        return count == n ? result : empty_list;
    }
private:
    bool check(int i, int m, string& s, string& t, vector<int>& result) 
    {
        bool change = false;
        for (int j = 0; j < m; j++) 
        {
            if (t[i + j] == '?') continue;
            if (t[i + j] != s[j]) return false;
            change = true;
        }
        if (change) 
        {
            for (int j = 0; j < m; j++) t[i + j] = '?';
            result.emplace_back(i);
        }
        return change;
    }
};

Java:

class Solution {
    public int[] movesToStamp(String stamp, String target) {
        int m = stamp.length(), n = target.length(), count = 0;
        char[] s = stamp.toCharArray(), t = target.toCharArray();
        List<Integer> list = new ArrayList<>();
        boolean change = true;
        while (change) {
            change = false;
            for (int i = 0; i < n - m + 1; i++) change |= check(i, m, s, t, list);
        }
        for (char c : t) if (c == '?') ++count;
        if (count < n) return new int[0];
        int p = list.size(), result[] = new int[p];
        for (int i = p - 1; i > -1; i--) result[p - i - 1] = list.get(i);
        return result;
    }
    
    private boolean check(int i, int m, char[] s, char[] t, List<Integer> list) {
        boolean result = false;
        for (int j = 0; j < m; j++) {
            if (t[i + j] == '?') continue;
            if (t[i + j] != s[j]) return false;
            result = true;
        }
        if (result) {
            for (int j = 0; j < m; j++) t[i + j] = '?';
            list.add(i);
        }
        return result;
    }
}

Python:

class Solution:
    def movesToStamp(self, stamp: str, target: str) -> List[int]:
        m, n, s, t, result, change = len(stamp), len(target), list(stamp), list(target), [], True

        def check(i: int) -> bool:
            change = False
            for j in range(m):
                if t[i + j] == "?": 
                    continue
                if t[i + j] != s[j]: 
                    return False
                change = True
            if change:
                t[i:i + m] = ["?"] * m
                result.append(i)
            return change

        while change:
            change = False
            for i in range(n - m + 1):
                change |= check(i)
        return result[::-1] if t.count("?") == n else []
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章