[LeetCode] Find And Replace in String 在字符串中查找和替換


 

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:

  1. 0 <= indexes.length = sources.length = targets.length <= 100
  2. 0 < indexes[i] < S.length <= 1000
  3. 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

https://leetcode.com/problems/find-and-replace-in-string/discuss/130577/C%2B%2B-5-lines-6-ms-bucket-sort-O(n)

https://leetcode.com/problems/find-and-replace-in-string/discuss/130587/C%2B%2BJavaPython-Replace-S-from-right-to-left

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM