LeetCode每日一题 2734.子串操作后的字典序最小字符串|标志位遍历字符数组

问题描述 📋

子串操作后的字典序最小字符串

给定一个仅包含小写字母的字符串,你可以执行如下操作任意次:

  1. 选择某个子串,将其中的每个字符都替换成其前一个字母(比如 ‘b’ 变成 ‘a’,‘c’ 变成 ‘b’,以此类推,‘a’ 变成 ‘z’)。

目标是通过最少的操作使得字符串变得字典序最小。🔠

解题思路 💡

为了将字符串变得字典序最小,我们可以遵循以下步骤:

  1. 寻找第一个非 ‘a’ 的字符:从左到右扫描字符串,找到第一个非 ‘a’ 的字符,并将其减一。这样操作可以保证尽可能早地对字符串进行优化,使其字典序最小。🕵️‍♂️
  2. 中断操作:在减一操作后,如果再次遇到 ‘a’,我们可以中断操作,因为继续操作下去可能会使字符串的字典序变大。🚫
  3. 特殊情况处理:如果整个字符串都是 ‘a’,我们可以将最后一个字符变成 ‘z’,使得结果字典序最小。🔚

为什么这样做?🤔

  • 尽早优化:通过尽早找到第一个非 ‘a’ 的字符并减一,可以确保字符串从最左边开始就变得更小,这样能最大程度上优化整个字符串的字典序。
  • 避免过度修改:如果在修改一个非 ‘a’ 的字符后继续修改其他字符,可能会导致字符串整体字典序变大。因此,在遇到 ‘a’ 后立即中断修改,以确保修改效果最佳。
  • 处理全 ‘a’ 字符串:对于全是 ‘a’ 的字符串,将最后一个字符变成 ‘z’ 可以使其变得字典序最小,这是一个边界情况的处理。
代码实现 💻
import scala.util.control.Breaks._

object Solution {
    def smallestString(s: String): String = {
        val chars = s.toCharArray
        var changed = false

        breakable {
            for (i <- chars.indices) {
                if (chars(i) != 'a') {
                    chars(i) = (chars(i) - 1).toChar
                    changed = true
                } else if (changed) {
                    break()
                }
            }
        }

        // If no character was changed, change the last character to 'z'
        if (!changed) {
            chars(s.length - 1) = 'z'
        }

        new String(chars)
    }
}
代码分析 🔍
  1. 字符数组转换:将字符串转换为字符数组,以便于直接修改。🔄
  2. 标志位 changed:用于记录是否进行了字符减一操作。📌
  3. 循环遍历和中断:使用 breakablebreak 控制循环,确保在第一次遇到非 ‘a’ 字符并进行减一操作后,遇到 ‘a’ 时中断操作。🛑
  4. 特殊情况处理:如果未进行任何字符修改操作,则将最后一个字符改为 ‘z’。📝
时空复杂度分析 ⏳💾
  • 时间复杂度:O(n),其中 n 是字符串的长度。因为在最坏情况下,我们需要遍历整个字符串一次。⌛️
  • 空间复杂度:O(n),用于存储字符数组。📂

通过这种方法,我们能够高效地解决问题,并确保字符串在经过最少的操作后,字典序最小。👍

#字符串操作 #字典序 #算法 #LeetCode解题 #Scala #编程技巧


希望这篇博客能够帮助你理解如何通过标志位和中断操作来高效地解决这个问题,进一步掌握字符串的操作技巧。欢迎在评论区分享你的看法和疑问!😊📘💬

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值