【833. 字符串中的查找与替换】

news2024/12/23 18:28:08

来源:力扣(LeetCode)

描述:

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

要完成第 i 个替换操作:

  1. 检查 子字符串 sources[i] 是否出现在 原字符串 s 的索引 indices[i] 处。
  2. 如果没有出现, 什么也不做
  3. 如果出现,则用 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:

1

输入:s = "abcd", indexes = [0,2], sources = ["a","cd"], targets = ["eee","ffff"]
输出:"eeebffff"
解释:
"a" 从 s 中的索引 0 开始,所以它被替换为 "eee""cd" 从 s 中的索引 2 开始,所以它被替换为 "ffff"

示例 2:
2

输入:s = "abcd", indexes = [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 <= indexes[i] < s.length
  • 1 <= sources[i].length, targets[i].length <= 50
  • s 仅由小写英文字母组成
  • sources[i] 和 targets[i] 仅由小写英文字母组成

方法一:按照下标排序 + 模拟

思路与算法

我们直接按照题目的要求进行模拟即可。

首先我们根据数组 indices,将所有的替换操作进行升序排序。在这一步中,同时对 indices,sources,targets 这三个数组进行排序较为困难,我们可以使用一个长度(记为 m)与它们相同的数组 ops,存储 0 到 m − 1 这 m 个下标,随后对 ops 本身按照 indices 作为第一关键字进行排序即可。

在排序完成后,我们就可以遍历给定的字符串 s 进行操作了。我们使用另一个指针 pt 指向 ops 的首个元素,表示当前需要进行的操作。当我们遍历到第 i 个字符时,我们首先不断往右移动 pt,直到其移出边界,或者第 ops[pt] 个操作的下标不小于 iii。此时,会有如下的两种情况:

  • 如果这个下标大于 i,说明不存在下标为 i 的操作。我们可以直接将第 i 个字符放入答案中;
  • 如果这个下标等于 i,说明存在下标为 i 的操作。我们将 s 从位置 i 开始的长度与 sources[ops[i]] 的子串与 sources[ops[i]] 进行比较:
    • 如果相等,那么替换操作成功,我们将 targets[ops[i]] 放入答案中。由于替换操作不可能重叠,因此我们可以直接跳过 sources[ops[i]] 长度那么多数量的字符;
    • 否则,替换操作失败,我们可以直接将第 i 个字符放入答案中。

需要注意的是,题目中只保证了成功的替换操作不会重叠,而不保证失败的替换操作不会重叠。因此当这个下标等于 i 时,可能会有多个替换操作需要进行尝试,即我们需要不断往右移动 pt,直到其移出边界,或者第 ops[pt] 个操作的下标严格大于 i。遍历到的替换操作需要依次进行尝试,如果其中一个成功,那么剩余的不必尝试,可以直接退出。

代码:

class Solution {
public:
    string findReplaceString(string s, vector<int>& indices, vector<string>& sources, vector<string>& targets) {
        int n = s.size(), m = indices.size();

        vector<int> ops(m);
        iota(ops.begin(), ops.end(), 0);
        sort(ops.begin(), ops.end(), [&](int i, int j) { return indices[i] < indices[j]; });

        string ans;
        int pt = 0;
        for (int i = 0; i < n;) {
            while (pt < m && indices[ops[pt]] < i) {
                ++pt;
            }
            bool succeed = false;
            while (pt < m && indices[ops[pt]] == i) {
                if (s.substr(i, sources[ops[pt]].size()) == sources[ops[pt]]) {
                    succeed = true;
                    break;
                }
                ++pt;
            }
            if (succeed) {
                ans += targets[ops[pt]];
                i += sources[ops[pt]].size();
            }
            else {
                ans += s[i];
                ++i;
            }
        }
        return ans;
    }
};

时间 0ms 击败 100.00%使用 C++ 的用户
内存 9.95mb 击败 88.18%使用 C++ 的用户
复杂度分析

  • 时间复杂度:O(n+mlog⁡m+ml),其中 n 是字符串 s 的长度,m 是数组 indices 的长度,l 是数组 sources 和 targets 中字符串的平均长度。
    - 排序需要的时间为 O(mlog⁡m);
    - 在使用双指针进行遍历的过程中,遍历字符串需要的时间为 O(n),遍历数组 ops 需要的时间为 O(m),在最坏情况下需要尝试每一个替换操作,比较和构造最终答案需要的时间为 O(ml)。
    相加即可得到总时间复杂度 O(n+mlogm+ml)。
  • 空间复杂度:O(n + ml)。
    - 数组 ops 需要的空间为 O(m);
    - 排序需要的栈空间为 O(log⁡m);
    - 在替换操作中进行比较时,如果使用的语言支持无拷贝的切片操作,那么需要的空间为 O(1),否则为 O(l);
    - 在构造最终答案时,如果使用的语言支持带修改的字符串,那么需要的空间为 O(1)(不考虑最终答案占用的空间),否则需要 O(n + ml) 的辅助空间。
    对于不同语言,上述需要的空间会有所变化。这里取每一种可能的最大值,相加即可得到总空间复杂度 O(n + ml)。

方法二:哈希表 + 模拟

思路与算法

我们也可以将方法一中的数组 ops 换成哈希映射,其中的键表示字符串中的下标,值是一个数组,存储了所有操作该下标的操作编号。我们只需要对数组 indices 进行一次遍历,就可以得到这个哈希表。

在这之后,当我们对字符串 s 进行遍历时,如果遍历到位置 i,那么哈希表中键 i 对应的数组,就是所有对位置 i 进行的操作。我们使用与方法一相同的方法处理这些操作即可。

代码:

class Solution {
public:
    string findReplaceString(string s, vector<int>& indices, vector<string>& sources, vector<string>& targets) {
        int n = s.size(), m = indices.size();

        unordered_map<int, vector<int>> ops;
        for (int i = 0; i < m; ++i) {
            ops[indices[i]].push_back(i);
        }

        string ans;
        for (int i = 0; i < n;) {
            bool succeed = false;
            if (ops.count(i)) {
                for (int pt: ops[i]) {
                    if (s.substr(i, sources[pt].size()) == sources[pt]) {
                        succeed = true;
                        ans += targets[pt];
                        i += sources[pt].size();
                        break;
                    }
                }
            }
            if (!succeed) {
                ans += s[i];
                ++i;
            }
        }
        return ans;
    }
};

时间 0ms 击败 100.00%使用 C++ 的用户
内存 10.12mb 击败 59.09%使用 C++ 的用户
复杂度分析

  • 时间复杂度:O(n+ml),其中 n 是字符串 s 的长度,m 是数组 indices 的长度,l 是数组 sources 和 targets 中字符串的平均长度。
  • 空间复杂度:O(n+ml)。
    author:力扣官方题解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/879891.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构:堆的实现

1.堆的概念 如果有一个关键码的集合 K { k1 &#xff0c;k2 &#xff0c;k3 &#xff0c;…&#xff0c;kn }&#xff0c;把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中&#xff0c;并且 k(i) < k(i*21) 和 k(i) < k(i*22)&#xff0c; i 0 &#xff…

人机融合中态、势、感、知的嵌套与级联

态、势、感、知四部分的嵌套与级联可以被看作是一种综合、协同的感知模式&#xff0c;它们相互作用并相互支持&#xff0c;共同构成了全面的态势感知能力。 "态"指的是事物或系统的状态或状况。它可以包括各种要素&#xff0c;如环境、情况、情绪等。态势感知中的“态…

vue中实现订单支付倒计时

需求 创建订单后15分钟内进行支付&#xff0c;否则订单取消。 实现 思路&#xff1a; 获取订单创建时间、在创建时间的基础上增加15分钟作为结束时间&#xff08;倒计时多久根据自己的实际需求&#xff0c;这里为15分钟&#xff09;&#xff0c;两时间戳相减获取间隔的毫秒数…

春秋云镜 CVE-2021-41947

春秋云镜 CVE-2021-41947 Subrion CMS v4.2.1 存在sql注入 靶标介绍 Subrion CMS v4.2.1 存在sql注入。 启动场景 漏洞利用 exp http://localhost/panel/visual-mode.json?getaccess&typeblocks UNION ALL SELECT username, password FROM sbr421_members -- -&o…

Vue学习之条件渲染

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>条件渲染</title><!--引入Vue--><script type"text/javascript" src"../vue.js"></script></head><body><!--…

Qt 屏幕偶发性失灵

项目场景: 基于NXP i.mx7的Qt应用层项目开发,通过goodix使用触摸屏,走i2c协议。 问题描述 触摸屏使用过程中意外卡死,现场分为多种: i2c总线传输错误,直观表现为触摸屏无效,任何与触摸屏挂接在同一总线上的i2c设备,均受到干扰,并且在传输过程中内核报错以下代码: G…

MAC环境,在IDEA执行报错java: -source 1.5 中不支持 diamond 运算符

Error:(41, 51) java: -source 1.5 中不支持 diamond 运算符 (请使用 -source 7 或更高版本以启用 diamond 运算符) 进入设置 修改java版本 pom文件中加入 <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin&l…

常见侧信道攻击方法

侧信道攻击方法需要采集到密码设备的能量泄露信息然后建立对应的能量消耗模型&#xff0c;之后使用特定的攻击方法来破解密钥。常见的侧信道攻击方法有简单能量&#xff08;或电磁&#xff09;攻击&#xff08;SPA&#xff09;、差分功耗&#xff08;或电磁&#xff09;攻击&am…

idea打jar包

目录 1、打包设置 2、打包介绍 3、开始打包 1、打包设置 先设置要打包的模块信息&#xff0c;即打包进去的内容。如下图所示&#xff1a;File --> Project Structure --> Artifacts&#xff0c;点击&#xff0b;号完成模块创建&#xff0c;其中有两种方式&#xff1a;…

【C++】STL---vector

STL---vector 一、vector 的介绍二、vector 的模拟实现1. 容量相关的接口&#xff08;1&#xff09;size&#xff08;2&#xff09;capacity&#xff08;3&#xff09;reserve&#xff08;4&#xff09;resize&#xff08;5&#xff09;empty 2. [] 重载3. 迭代器4. 修改数据相…

【二开】jeecgboot 开发过程方法扩展二开整理

【二开】jeecgboot 开发过程方法扩展二开整理 org.jeecg.modules.system.controller.CommonController#upload 可以二开统一文件上传 返回值增加文件大小 跟文件名称 //自定义 图片前缀savePath jeecgBaseConfig.getUploadRequestHost() savePath;if(oConvertUtils.isNotEm…

选择任务管理软件:哪个更适合你的需求?

随着互联网的发展&#xff0c;知识管理是可以成为企业获得更大发展前景的神兵利器&#xff0c;任务协同&#xff0c;是服务于中小型团队&#xff0c;或者大型机构的终端组织。来看看这款国外流行的任务管理软件Zoho Projects。 任务管理是企业协同的重要组成部分。 任务管理是企…

如何正确下载tomcat???

亲爱的小伙伴&#xff0c;千万别再去找下网站下载啦&#xff0c;这样詪容易携带病毒。 我们去官方网址下载。 Apache Tomcat - Welcome! 最后下载解压即可。。。

免费机器人来了(基于有限状态机),快来体验下

免费有限状态机机器人来了,快来体验下 51jiqiren.cn 五分钟就可以完成一个简单的机器人. 懂json的同学可以自定义状态和状态跳转,完成复杂的业务流程. 更多功能还在开发中. 网站右下角点"联系客服"截图: 弹出来了: 后端管理界面: 有限状态机界面: 数据界面: 在网…

论文复现--关于单视角动作捕捉工具箱--MMHuman3d的研究(基于Windows10和Linux18.04中配置)

分类&#xff1a;动作捕捉 github地址&#xff1a;https://github.com/open-mmlab/mmhuman3d 所需环境&#xff1a; Windows10&#xff0c;CUDA11.6&#xff0c;conda 4.13.0&#xff0c;Visual Studio 2017&#xff1b; Ubuntu18.04&#xff0c;conda22.9.0&#xff0c;CUDA11…

企业网盘 vs 传统存储设备:为何云存储成为首选?

企业网盘的出现为企业提供了新的存储方式&#xff0c;相较于传统的存储设备&#xff0c;为何越来越多的企业选择了云存储呢&#xff1f; 一、存储成本 在企业数据存储方面&#xff0c;成本是企业重要的考量因素。企业网盘是基于云存储技术的存储工具&#xff0c;因此它比传统的…

算法(第4版)练习题 1.1.27 的三种解法

本文列举了对于 算法 : 第4版 / (美) 塞奇威客 (Sedgewick, R.) , (美) 韦恩 (Wayne, K.) 著 ; 谢路云译. -- 北京 : 人民邮电出版社, 2012.10 (2021.5重印)&#xff08;以下简称原书或书&#xff09;中的练习题 1.1.27 的三种解法&#xff08;C 实现&#xff09;&#xff0c;并…

朴素贝叶斯(右心室肥厚的辅助识别)

现在我们判断右心室是否肥厚通常的做法都是借助心电图来识别&#xff0c;左侧的是右心室肥厚的&#xff0c;右侧的是右心室厚度正常&#xff0c;那接下来就要按照给出的图像来处理特征&#xff0c;提取出正常组和肥厚组的不同特征。 根据上图我们可以得出通过图像提取出了年龄…

〔AI 绘画〕Stable Diffusion 之 VAE 篇

✨ 目录 &#x1f388; 什么是VAE&#x1f388; 开启VAE&#x1f388; 下载常见的VAE&#x1f388; 对比不同VAE生成的效果 &#x1f388; 什么是VAE VAE&#xff1a;是 Variational Auto-Encoder 的简称&#xff0c;也就是变分自动编码器可以把它理解成给图片加滤镜&#xff…

KCC@深圳开源读书会即将举办,来与行业大咖面对面交流

KCC&#xff0c;全称 KAIYUANSHE City Community&#xff08;中文&#xff1a;开源社城市社区&#xff09;是由开源社发起&#xff0c;旨在让开源社区在每个城市落地生根的地域性开源组织。 自2023年2月份发起以来&#xff0c;我们已经在南京、上海、深圳、北京、硅谷、新加坡、…