给定一个字符串,对该字符串进行删除操作,保留 k 个字符且相对位置不变,使字典序最小

news/2025/1/10 9:24:03/

这是一个经典的编程问题,可以用 单调栈 的方法高效解决。以下是解题步骤和代码实现:


问题描述

给定一个字符串 s 和一个整数 k,要求删除字符串中的一些字符,最终保留 k 个字符,且相对顺序不变,使得结果字符串字典序最小。


解题思路

  1. 单调栈维护最小字典序

    • 使用一个栈来维护当前最小的字典序字符。
    • 遍历字符串 s,尝试将每个字符压入栈。
    • 如果栈顶字符大于当前字符,并且后面还有足够的字符可以填满栈,则弹出栈顶字符。
    • 最终栈中保留的就是字典序最小的字符。
  2. 边界条件

    • 栈的大小不能超过 k
    • 遍历时要确保剩下的字符足够填满栈(栈中已保留字符 + 剩余未处理字符 >= k)。

Python代码实现

python">def removeToKeepKMin(s: str, k: int) -> str:stack = []  # 用于存放最终结果字符的栈n = len(s)  # 字符串长度for i, char in enumerate(s):# 当栈非空,且栈顶字符比当前字符大,且后面还有足够字符时,可以弹出栈顶while stack and stack[-1] > char and len(stack) + (n - i) > k:stack.pop()# 如果栈长度小于k,则可以压入当前字符if len(stack) < k:stack.append(char)# 最终栈中的字符就是结果return ''.join(stack)

示例

示例 1
python">s = "bcabc"
k = 3
print(removeToKeepKMin(s, k))  # 输出: "abc"

解释:

  • 删除字符串中的第一个 'b' 和第二个 'c',保留 "abc",使得字典序最小。
示例 2
python">s = "cbacdcbc"
k = 4
print(removeToKeepKMin(s, k))  # 输出: "acdb"

解释:

  • 删除字符 'c''b' 后,保留 "acdb",使得字典序最小。

复杂度分析

  1. 时间复杂度:O(n),每个字符最多入栈一次,出栈一次。
  2. 空间复杂度:O(k),栈的最大大小为 k

这个问题也可以通过动态规划(DP)来解决。不过相较于单调栈,动态规划的时间复杂度和实现相对更复杂一些。

以下是动态规划的解法思路:


动态规划解法思路

状态定义

我们定义一个二维数组 dp[i][j] 表示从字符串的前 i 个字符中,选择 j 个字符所能获得的字典序最小的字符串。

  • i 是字符串前缀长度;
  • j 是要保留的字符个数;
  • dp[i][j] 表示从前 i 个字符中选 j 个字符的最优解(字典序最小)。
状态转移

在遍历字符串的过程中,对于每个字符,我们有两种选择:

  1. 不选当前字符:如果不选当前字符,那么问题退化为从前 i-1 个字符中选择 j 个字符,即 dp[i][j] = dp[i-1][j]
  2. 选当前字符:如果选当前字符,那么我们需要从前 i-1 个字符中选择 j-1 个字符,再加上当前字符,即 dp[i][j] = dp[i-1][j-1] + s[i-1]

状态转移方程如下:
[
dp[i][j] = \min(dp[i-1][j], dp[i-1][j-1] + s[i-1])
]

边界条件
  1. j == 0(不保留字符时),结果为空字符串:dp[i][0] = ""
  2. i == 0j > 0(字符串为空时,无法选择任何字符):dp[0][j] 不存在,为无穷大(不可达)。
最终结果

最后的答案是 dp[n][k],其中 n 是字符串长度,k 是要保留的字符数。


动态规划代码实现

以下是基于上述思路的 Python 实现:

python">def removeToKeepKMinDP(s: str, k: int) -> str:n = len(s)# dp[i][j] 表示从前 i 个字符中选择 j 个字符的字典序最小字符串dp = [["" for _ in range(k + 1)] for _ in range(n + 1)]# 初始化边界条件for i in range(n + 1):dp[i][0] = ""  # 选择 0 个字符时为空字符串for j in range(1, k + 1):dp[0][j] = "~"  # 不可能从空字符串中选择字符,用 "~" 表示无穷大(字典序最大字符)# 动态规划填表for i in range(1, n + 1):for j in range(1, k + 1):# 如果不选当前字符option1 = dp[i-1][j]# 如果选当前字符option2 = dp[i-1][j-1] + s[i-1] if j <= i else "~"  # 保证 j <= i# 取字典序最小的结果dp[i][j] = min(option1, option2)return dp[n][k]

示例

示例 1
python">s = "bcabc"
k = 3
print(removeToKeepKMinDP(s, k))  # 输出: "abc"

过程

  1. 初始化 dp 表:
    • dp[i][0] 初始化为 ""
    • dp[0][j] 初始化为 "~"
  2. 填表,逐步从前缀中选择字符并更新最优解。
  3. 最终 dp[5][3] = "abc"

示例 2
python">s = "cbacdcbc"
k = 4
print(removeToKeepKMinDP(s, k))  # 输出: "acdb"

时间复杂度

  1. 时间复杂度:O(n * k),n 是字符串长度,k 是需要保留的字符数。
    • 每个 dp[i][j] 都取决于上一步的状态,因此需要遍历整个 dp 表。
  2. 空间复杂度:O(n * k),用于存储 dp 表。

相比单调栈方法,动态规划的复杂度更高,但它提供了更通用的思路,能够很好地解决其他类似问题。


总结

  • 如果问题的输入规模较小,可以使用动态规划方法。
  • 如果需要更高效的实现,单调栈是更优的选择,时间复杂度为 O(n),空间复杂度为 O(k)。

http://www.ppmy.cn/news/1561954.html

相关文章

从低危Blind SSRF到严重漏洞

视频教程在我主页简介或专栏里 SSRF简介 服务器端请求伪造&#xff08;SSRF&#xff09;是一种Web安全漏洞&#xff0c;它允许攻击者使服务器端应用程序向非预期的位置发送请求。这可能导致攻击者迫使服务器连接到组织内部基础设施中仅限内部访问的服务。在其他情况下&#xf…

Maven核心与单元测试

目录 一. Maven概述二. IDEA集成Maven2.1 创建Maven项目2.2 Maven坐标2.3 导入Maven项目 三. 依赖管理四. Maven的生命周期五. 单元测试5.1 快速入门5.2 断言5.3 常见注解5.4 依赖范围 六. Maven常见问题 \quad 一. Maven概述 \quad \quad 二. IDEA集成Maven \quad 2.1 创建Mav…

python无需验证码免登录12306抢票 --selenium(2)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 [TOC](python无需验证码免登录12306抢票 --selenium(2)) 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 就在刚刚我抢的票&#xff1a;2025年1月8日…

游戏引擎学习第75天

仓库:https://gitee.com/mrxiao_com/2d_game_2 Blackboard: 处理楼梯通行 为了实现楼梯的平滑过渡和角色的移动控制&#xff0c;需要对楼梯区域的碰撞与玩家的运动方式进行优化。具体的处理方式和遇到的问题如下&#xff1a; 楼梯区域的过渡&#xff1a; 在三维空间中&#x…

ubuntu设置开机无需输入密码自启动todesk

1.进入/etc/init.d/目录 cd /etc/init.d/ 2.新建一个自定义名称的sh脚本&#xff0c;这里以 start_todesk 名称为例建立一个 start_todesk.sh 的脚本 sudo vim start_todesk.sh3.将以下内容写入 ### BEGIN INIT INFO # Provides: svnd.sh # Required-start: $lo…

VBA之Word应用第三章第五节:文档Document对象的属性(二)

《VBA之Word应用》&#xff08;版权10178982&#xff09;&#xff0c;是我推出第八套教程&#xff0c;教程是专门讲解VBA在Word中的应用&#xff0c;围绕“面向对象编程”讲解&#xff0c;首先让大家认识Word中VBA的对象&#xff0c;以及对象的属性、方法&#xff0c;然后通过实…

vue之element-ui文件上传(二)

一、点击上传&#xff0c;使用默认的action上传&#xff0c;添加校验&#xff0c;上传成功后&#xff0c;去除校验&#xff1a; <el-form-item label"文件md5" prop"fileMd5"><el-uploadv-if"!form.fileMd5"v-model"form.fileMd5&…

如何制作一份出色的公司介绍PPT?

制作一份公司介绍的PPT需要精心设计&#xff0c;以确保内容既专业又吸引人。以下是一个基本的框架和一些建议&#xff0c;帮助您创建一份有效的公司介绍PPT&#xff1a; PPT标题页 标题&#xff1a;公司全称&#xff08;可使用公司Logo作为背景或嵌入标题中&#xff09;副标题…