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 []