C++算法:字符串中的查找与替换

简介: C++算法:字符串中的查找与替换

题目

你会得到一个字符串 s (索引从 0 开始),你必须对它执行 k 个替换操作。替换操作以三个长度均为 k 的并行数组给出:indices, sources, targets。

要完成第 i 个替换操作:

检查 子字符串 sources[i] 是否出现在 原字符串 s 的索引 indices[i] 处。

如果没有出现, 什么也不做 。

如果出现,则用 targets[i] 替换 该子字符串。

例如,如果 s = “abcd” , indices[i] = 0 , sources[i] = “ab”, targets[i] = “eee” ,那么替换的结果将是 “eeecd” 。

所有替换操作必须 同时 发生,这意味着替换操作不应该影响彼此的索引。测试用例保证元素间不会重叠 。

例如,一个 s = “abc” , indices = [0,1] , sources = [“ab”,“bc”] 的测试用例将不会生成,因为 “ab” 和 “bc” 替换重叠。

在对 s 执行所有替换操作后返回 结果字符串 。

子字符串 是字符串中连续的字符序列。

示例 1:

输入:s = “abcd”, indices = [0,2], sources = [“a”,“cd”], targets = [“eee”,“ffff”]

输出:“eeebffff”

解释:

“a” 从 s 中的索引 0 开始,所以它被替换为 “eee”。

“cd” 从 s 中的索引 2 开始,所以它被替换为 “ffff”。

示例 2:

输入:s = “abcd”, indices = [0,2], sources = [“ab”,“ec”], targets = [“eee”,“ffff”]

输出:“eeecd”

解释:

“ab” 从 s 中的索引 0 开始,所以它被替换为 “eee”。

“ec” 没有从原始的 S 中的索引 2 开始,所以它没有被替换。

参数范围

1 <= s.length <= 1000

k == indices.length == sources.length == targets.length

1 <= k <= 100

0 <= indices[i] < s.length

1 <= sources[i].length, targets[i].length <= 50

s 仅由小写英文字母组成

sources[i] 和 targets[i] 仅由小写英文字母组成

分析

将 indices sources targets 按indices的升序排序。可以只对索引排序。

然后依次枚举indices

a,将前面未处理的数据复制到结果串。

b,如果和源串相同则将目标串复制到结果。

c,如果和源串不同,则复制原始串到结果。

变量解释

iNeedDo 未处理的字符起始位置。

代码

class CIndexVector
{
public:
template
CIndexVector(vector& data)
{
for (int i = 0; i < data.size(); i++)
{
m_indexs.emplace_back(i);
}
std::sort(m_indexs.begin(), m_indexs.end(), [&data](const int& i1, const int& i2)
{
return data[i1] < data[i2];
});
}
vector m_indexs;
};
class Solution {
public:
string findReplaceString(string s, vector& indices, vector& sources, vector& targets) {
CIndexVector indexs(indices);
int iNeedDo = 0;
string strRet;
for (auto& i : indexs.m_indexs)
{
const int len = indices[i] - iNeedDo;
if (len > 0)
{
strRet += s.substr(iNeedDo, len);
iNeedDo += len;
}
if (s.substr(indices[i], sources[i].length()) == sources[i])
{
strRet += targets[i];
iNeedDo += sources[i].length();
}
}
strRet += s.substr(iNeedDo);
return strRet;
}
};

测试用例

void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}
template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
Assert(v1[i], v2[i]);
}
}
int main()
{
vector events;
int k;
string res;
{
Solution slu;
string s = “abcd”;
vector indices = { 0, 2 };
vector sources = { “a”, “cd” }, targets = { “eee”, “ffff” };
res = slu.findReplaceString(s, indices, sources, targets);
Assert(res, string(“eeebffff”));
}
{
Solution slu;
string s = “vmokgggqzp”;
vector indices = { 3, 5, 1 };
vector sources = { “kg”, “ggq”, “mo” }, targets = { “s”, “so”, “bfr” };
res = slu.findReplaceString(s, indices, sources, targets);
Assert(res, string(“vbfrssozp”));
}
//CConsole::Out(res);

}

优化版

直接替换,注意 从后向前替换,避免索引发生变化。

s.replace 有多个版本,前两个参数是迭代器的替换左闭右开空间,是整数则是按起始位置和长度替换。

class CIndexVector
{
public:
  template<class ELE >
  CIndexVector(vector<ELE>& data)
  {
    for (int i = 0; i < data.size(); i++)
    {
      m_indexs.emplace_back(i);
    }
    std::sort(m_indexs.begin(), m_indexs.end(), [&data](const int& i1, const int& i2)
      {
        return data[i1] < data[i2];
      });
  }
  vector<int> m_indexs;
};
class Solution {
public:
  string findReplaceString(string s, vector<int>& indices, vector<string>& sources, vector<string>& targets) {
    CIndexVector indexs(indices);
    for (int i = indexs.m_indexs.size()-1; i >= 0 ; i-- )
    {
      const int index = indexs.m_indexs[i];
      const int len = sources[index].length();
      if (s.substr(indices[index], len) == sources[index])
      {
        s.replace(s.begin()+indices[index], s.begin() + indices[index] + len, targets[index]);
      }
    }
    return s;
  }
};

2022年12月旧版

class Solution {
public:
string findReplaceString(string s, vector& indices, vector& sources, vector& targets) {
string sRet;
const int c = indices.size();
vector idxs;
for (int i = 0; i < c; i++)
{
idxs.push_back(i);
}
std::sort(idxs.begin(), idxs.end(), [&indices](const int& i1,const int& i2){
return indices[i1] < indices[i2];
});
int j = 0;
for (int i = 0; i < c; i++)
{
const int& idx = idxs[i];
while (j < indices[idx])
{
sRet += s[j++];
}
string tmp = s.substr(indices[idx], sources[idx].length());
if (tmp == sources[idx])
{
sRet += targets[idx];
j += tmp.length();
}
}
while (j < s.length())
{
sRet += s[j++];
}
return sRet;
}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。

https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程

https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版

https://download.csdn.net/download/he_zhidan/88348653


相关文章
|
1月前
|
算法
两个字符串匹配出最长公共子序列算法
本文介绍了最长公共子序列(LCS)问题的算法实现,通过动态规划方法求解两个字符串的最长公共子序列,并提供了具体的编程实现细节和示例。
73 1
两个字符串匹配出最长公共子序列算法
|
1月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
406 0
高精度算法(加、减、乘、除,使用c++实现)
|
1月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
22 0
|
1月前
|
缓存 网络协议 API
C/C++ StringToAddress(字符串转 boost::asio::ip::address)
通过上述步骤和示例代码,你可以轻松地在C++项目中实现从字符串到 `boost::asio::ip::address`的转换,从而充分利用Boost.Asio库进行网络编程。
52 0
|
1月前
|
存储 算法 决策智能
【算法】博弈论(C/C++)
【算法】博弈论(C/C++)
|
1月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
|
1月前
|
机器学习/深度学习 人工智能 算法
【算法】最长公共子序列(C/C++)
【算法】最长公共子序列(C/C++)
|
1月前
|
人工智能 算法 BI
一篇带你速通差分算法(C/C++)
一篇带你速通差分算法(C/C++)
|
1月前
|
人工智能 算法 C++
一篇带你速通前缀和算法(C/C++)
一篇带你速通前缀和算法(C/C++)
|
1月前
|
存储 算法 C++
弗洛伊德(Floyd)算法(C/C++)
弗洛伊德(Floyd)算法(C/C++)