[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:
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 = ; 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(, 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 = ; 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(, 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 = ; i < indexes.size(); ++i) {
if (S.substr(indexes[i], sources[i].size()) == sources[i]) {
m[indexes[i]] = i;
}
}
for (int i = ; 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 = ; 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
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Find And Replace in String 在字符串中查找和替换的更多相关文章
- hiho1482出勤记录II(string类字符串中查找字符串,库函数的应用)
string类中有很多好用的函数,这里介绍在string类字符串中查找字符串的函数. string类字符串中查找字符串一般可以用: 1.s.find(s1)函数,从前往后查找与目标字符串匹配的第一个位 ...
- [LeetCode] Reverse Words in a String 翻转字符串中的单词
Given an input string, reverse the string word by word. For example, Given s = "the sky is blue ...
- [LeetCode] Unique Substrings in Wraparound String 封装字符串中的独特子字符串
Consider the string s to be the infinite wraparound string of "abcdefghijklmnopqrstuvwxyz" ...
- [LeetCode] Reverse Vowels of a String 翻转字符串中的元音字母
Write a function that takes a string as input and reverse only the vowels of a string. Example 1:Giv ...
- leetcode——Reverse Words in a String 旋转字符串中单词顺序(AC)
题目例如以下: Given an input string, reverse the string word by word. For example, Given s = "the sky ...
- 将一个字符串中的空格替换成“%20”(C、Python)
将一个字符串中的空格替换成“%20” C语言: /* ----------------------------------- 通过函数调用,传地址来操作字符串 1.先计算出替换后的字符串的长度 2.从 ...
- 实现字符串的查找和替换 分类: c/c++ 2014-10-09 22:33 469人阅读 评论(0) 收藏
在字符串中查找目标字符串并将其替换为指定字符串,返回替换的次数.接口为 int find_str_replace(char *&str,const char *find_str,const c ...
- 《剑指offer面试题4》替换空格——实现函数把字符串中每个空格替换成“%20”
思路: 例如把we are happy这个字符串中所有空格替换成"%20",最直接的做法是从头开始扫苗,遇到空格就替换,并且把空格后面的字符都顺序后移.复杂度O(n^2). 重要思 ...
- sh_17_字符串的查找和替换
sh_17_字符串的查找和替换 hello_str = "hello world" # 1. 判断是否以指定字符串开始 print(hello_str.startswith(&qu ...
随机推荐
- Linux服务器查看外网IP地址的命令
可以直接输入如下几个命令:1.curl ifconfig.me2.curl cip.cc3.curl icanhazip.com4.curl ident.me5.curl ipecho.net/pla ...
- 51nod 2513
写代码的时候抄错变量,晕! 另外有个while循环条件错的,因为两个指针必须都要有终止条件 代码: #include<iostream> #include<cstdio> #i ...
- ABP代码生成器与升级到VS2017VSIX
首先,我不是要分享一个代码生成器,而是怎么升级到VS2017,简单介绍下 如何将2015的VSIX项目升级到2017 阳光铭睿 写了一篇<分享一个与ABP配套使用的代码生成器源码>,并在群 ...
- Beta答辩总结
组员名单 短学号 姓名 备注 409 后敬甲 组长 301 蔡文斌 315 黄靖茹 423 刘浩 317 黄泽 328 卢泽明 617 葛亮 344 张杰 348 朱跃安 链接汇总 组长博客:后敬甲 ...
- ubuntu 配置apt-get源
ubantu安装软件速度慢一般是因为系统默认选择的源导致,可以通过手动配置源设置解决. 1. 原文件备份 sudo mv /etc/apt/sources.list /etc/apt/sources. ...
- 项目debug启动不起来解决办法
debug起服务,读取文件可能会出错,eclipse自动加断点,这时候就卡住了,这时候eclipse——window——show view breakpoints-——remove all,重新启动t ...
- C# 高级编程01----.Net基础介绍
一.C#与.Net 的关系 1)C#语言 1. C#是一种简洁.类型安全的面向对象语言,可以使用C#语言创建可以在.Net Framework上运行的应用程序 2. C# 语言功能取决于.Net 的功 ...
- 2018年最新JAVA面试题总结之JavaWeb(2)
转自于:https://zhuanlan.zhihu.com/p/39522575 1.tomcat的优化方式?回答:Tomcat的优化我准备从三方面来说: 第一部分: 内存优化Tomcat的默认内存 ...
- js事件流机制冒泡和捕获
JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间. 事件流 从页面中接收事件的顺序称为事件流. IE --> 事件冒泡流 Netsc ...
- git 仓库中删除历史大文件
git 仓库中删除历史大文件 在git中增加了一个很大的文件,而且被保存在历史提交记录中,每次拉取代码都很大,速度很慢.而且用删除 提交历史记录的方式不是很实际. 以下分几个步骤介绍如何减小.git文 ...