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

279 阅读3分钟

🎈 算法并不一定都是很难的题目,也有很多只是一些代码技巧,多进行一些算法题目的练习,可以帮助我们开阔解题思路,提升我们的逻辑思维能力,也可以将一些算法思维结合到业务代码的编写思考中。简而言之,平时进行的算法习题练习带给我们的好处一定是不少的,所以让我们一起来养成算法练习的习惯。今天练习的题目是一道比较简单的题目 ->执行子串操作后的字典序最小字符串

问题描述

给你一个仅由小写英文字母组成的字符串  s 。在一步操作中,你可以完成以下行为:

  • 选择  s  的任一非空子字符串,可能是整个字符串,接着将字符串中的每一个字符替换为英文字母表中的前一个字符。例如,'b' 用 'a' 替换,'a' 用 'z' 替换。

返回执行上述操作  恰好一次  后可以获得的  字典序最小  的字符串。

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

现有长度相同的两个字符串  x  和 字符串  y ,在满足  x[i] != y[i]  的第一个位置  i  上,如果   x[i]  在字母表中先于  y[i]  出现,则认为字符串  x  比字符串  y 字典序更小 。

示例 1:

输入: s = "cbabc"
输出: "baabc"
解释: 我们选择从下标 0 开始、到下标 1 结束的子字符串执行操作。
可以证明最终得到的字符串是字典序最小的。

示例 2:

输入: s = "acbbc"
输出: "abaab"
解释: 我们选择从下标 1 开始、到下标 4 结束的子字符串执行操作。
可以证明最终得到的字符串是字典序最小的。

示例 3:

输入: s = "leetcode"
输出: "kddsbncd"
解释: 我们选择整个字符串执行操作。
可以证明最终得到的字符串是字典序最小的。

提示:

  • 1 <= s.length <= 3 * 10^5
  • s  仅由小写英文字母组成

思路分析

首先我们应该要先理解一下题目意思,题目会给我们一个字符串 s,我们需要对字符串 s 进行一次操作:选择  s  的任一非空子字符串,可能是整个字符串,接着将字符串中的每一个字符替换为英文字母表中的前一个字符。例如,'b' 用 'a' 替换,'a' 用 'z' 替换,我们希望得到字典序最小  的字符串。

我们要先思考一下什么情况下进行操作字符串的字典序会变小,因为我们操作是将字符串中的每一个字符替换为英文字母表中的前一个字符,所以除开 a 字符变成 z 字符是字典序会变大,其他字符串替换成其前一个字符,都会使其字典序变小,而要使得到的字符串字典序最小  的话,我们则需要替换字符串最靠前的不含 a 的连续字符串。

这里主要分为两种情况:

  • 1、字符串中有不为a的子串

所以我们可以遍历字符串,找到第一个不等于a的字符,以其作为起始字符继续向后遍历,找到一串不含a的字符串,将字符串中的字符都改为其前一个字符,其余字符都保持不变,这样得到的字符串就是通过一次操作所能得到字典序最小的字符串了,具体代码如下:

let res = "";
for (let i = 0; i < s.length; i++) {
  if (s[i] > "a") {
    while (s[i] > "a") {
      const num = s[i].charCodeAt() - 97 - 1 + 26;
      res += String.fromCharCode((num % 26) + 97);
      i++;
    }
    res += s.slice(i);
    return res;
  } else {
    res += s[i];
  }
}
  • 2、字符串中全都是a字符

因为a变为z的话是会将原字符串的字典序变大的,所以我们应该选择最后一个字符进行操作,其余字符都保持不变,这样得到的字符串就是通过一次操作所能得到字典序最小的字符串了,具体代码如下:

const len = s.length - 1;
let ans = s.slice(0, len);
const num = s[len].charCodeAt() - 97 - 1 + 26;
ans += String.fromCharCode((num % 26) + 97);
return ans;

AC 代码

完整 AC 代码如下:

/**
 * @param {string} s
 * @return {string}
 */
var smallestString = function (s) {
  let res = "";
  for (let i = 0; i < s.length; i++) {
    if (s[i] > "a") {
      while (s[i] > "a") {
        const num = s[i].charCodeAt() - 97 - 1 + 26;
        res += String.fromCharCode((num % 26) + 97);
        i++;
      }
      res += s.slice(i);
      return res;
    } else {
      res += s[i];
    }
  }
  const len = s.length - 1;
  let ans = s.slice(0, len);
  const num = s[len].charCodeAt() - 97 - 1 + 26;
  ans += String.fromCharCode((num % 26) + 97);
  return ans;
};

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,在此谢谢大家的支持,我们下文再见 🙌。