To some string S
, we will perform some replacement operations that replace groups of letters with new ones (not necessarily the same size).
Each replacement operation has 3
parameters: a starting index i
, a source word x
and a target word y
. The rule is that if x
starts at position i
in the original string S
, then we will replace that occurrence of x
with y
. If not, we do nothing.
For example, if we have S = "abcd"
and we have some replacement operation i = 2, x = "cd", y = "ffff"
, then because "cd"
starts at position 2
in the original string S
, we will replace it with "ffff"
.
Using another example on S = "abcd"
, if we have both the replacement operation i = 0, x = "ab", y = "eee"
, as well as another replacement operation i = 2, x = "ec", y = "ffff"
, this second operation does nothing because in the original string S[2] = 'c'
, which doesn't match x[0] = 'e'
.
All these operations occur simultaneously. It's guaranteed that there won't be any overlap in replacement: for example, S = "abc", indexes = [0, 1], sources = ["ab","bc"]
is not a valid test case.
Example 1:
Input: S = "abcd", indexes = [0,2], sources = ["a","cd"], targets = ["eee","ffff"] Output: "eeebffff" Explanation: "a" starts at index 0 in S, so it's replaced by "eee". "cd" starts at index 2 in S, so it's replaced by "ffff".
Example 2:
Input: S = "abcd", indexes = [0,2], sources = ["ab","ec"], targets = ["eee","ffff"] Output: "eeecd" Explanation: "ab" starts at index 0 in S, so it's replaced by "eee". "ec" doesn't starts at index 2 in the original S, so we do nothing.
Notes:
0 <= indexes.length = sources.length = targets.length <= 100
0 < indexes[i] < S.length <= 1000
- All characters in given inputs are lowercase letters.
這道題給了我們一個字符串S,並給了一個坐標數組,還有一個源字符串數組,還有目標字符串數組,意思是若某個坐標位置起,源字符串數組中對應位置的字符串出現了,將其替換為目標字符串。題目真的是好長,但好在給了兩個例子可以幫助我們很好的理解題意。此題的核心操作就兩個,查找和替換,需要注意的是,由於替換操作會改變原字符串,但是我們查找始終是基於最初始的S,比如例子2中,當完成了第一次替換后,S變為了 "eeecd",好像此時 "ec" 出現了,但仍然不能替換,因為一切查找都是基於最原始的那個S。那么正向的替換可能會產生這樣的問題,我們注意到題目中有個限制條件,就是說不會有重疊產生,比如 "abc",如果讓在0位置上查找 "ab" 了,就不會讓在1位置上查找 "bc",這樣的話,其實我們可以從后往前開始查找替換,因為不會有重疊,所以后面替換了的字符不會影響到前面。首先我們需要給indexes數組排個序,因為可能不是有序的,但是卻不能直接排序,這樣會丟失和sources,targets數組的對應關系,這很麻煩。所以我們新建了一個保存pair對兒的數組,將indexes數組中的數字跟其位置坐標組成pair對兒,加入新數組v中,然后給這個新數組按從大到小的方式排序,這樣我們既排了序,又保存了對應關系,豈不美哉!
下面就要開始遍歷新數組v了,對於遍歷到的pair對兒,取出第一個數字,保存到i,表示S中需要查找的位置,取出第二個數字,然后根據這個位置分別到sources和targets數組中取出源字符串和目標字符串,然后我們在S中的i位置,向后取出和源字符串長度相同的子串,然后比較,若正好和源字符串相等,則將其替換為目標字符串即可,參見代碼如下:
解法一:
class Solution { public: string findReplaceString(string S, vector<int>& indexes, vector<string>& sources, vector<string>& targets) { vector<pair<int, int>> v; for (int i = 0; i < indexes.size(); ++i) { v.push_back({indexes[i], i}); } sort(v.rbegin(), v.rend()); for (auto a : v) { int i = a.first; string s = sources[a.second], t = targets[a.second]; if (S.substr(i, s.size()) == s) { S = S.substr(0, i) + t + S.substr(i + s.size()); } } return S; } };
我們也可以使用TreeMap來代替需要排序的數組,由於TreeMap默認的是最小堆,而我們需要的是最大堆,只要在定義上加一個greater就行了,其他部分基本沒有任何的區別,參見代碼如下:
解法二:
class Solution { public: string findReplaceString(string S, vector<int>& indexes, vector<string>& sources, vector<string>& targets) { map<int, int, greater<int>> m; for (int i = 0; i < indexes.size(); ++i) { m[indexes[i]] = i; } for (auto a : m) { int i = a.first; string s = sources[a.second], t = targets[a.second]; if (S.substr(i, s.size()) == s) { S = S.substr(0, i) + t + S.substr(i + s.size()); } } return S; } };
再來看一種稍有不同的解法,之前的兩種解法都是直接在S上替換,這里我們新建一個結果res字符串,這里還是使用HashMap來保存映射對,但是稍有不同的是,我們並不是無腦的添加所有的映射對兒,而是先做個check,只要當發現可以查找到源字符串位置的時候,才添加映射對兒,這樣就排除了所有不能替換的情況。然后我們遍歷原字符串S,對於每個遍歷到的位置,我們都到HashMap中查找,如果發現需要替換,我們就把目標字符串提取出來,加入結果res中,注意此時i也需要加上源字符串的長度。若不需要替換,則直接將字符加入結果res中,然后i移動到下一個位置,參見代碼如下:
解法三:
class Solution { public: string findReplaceString(string S, vector<int>& indexes, vector<string>& sources, vector<string>& targets) { string res = ""; unordered_map<int, int> m; for (int i = 0; i < indexes.size(); ++i) { if (S.substr(indexes[i], sources[i].size()) == sources[i]) { m[indexes[i]] = i; } } for (int i = 0; i < S.size();) { if (m.count(i)) { res += targets[m[i]]; i += sources[m[i]].size(); } else { res.push_back(S[i]); ++i; } } return res; } };
我們也可以使用STL自帶的replace函數來完成替換操作,有點偷懶啊~
解法四:
class Solution { public: string findReplaceString(string S, vector<int>& indexes, vector<string>& sources, vector<string>& targets) { map<int, pair<int, string>, greater<int>> m; for (int i = 0; i < indexes.size(); ++i) { if (S.substr(indexes[i], sources[i].size()) == sources[i]) { m[indexes[i]] = {sources[i].size(), targets[i]}; } } for (auto a : m) { S.replace(a.first, a.second.first, a.second.second); } return S; } };
參考資料:
https://leetcode.com/problems/find-and-replace-in-string/
https://leetcode.com/problems/find-and-replace-in-string/discuss/134758/Java-O(n)-solution