leetcode
leetcode 2351 ~ 2400
执行子串操作后的字典序最小字符串

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

难度:

标签:

题目描述

You are given a string s consisting of only lowercase English letters. In one operation, you can do the following:

  • Select any non-empty substring of s, possibly the entire string, then replace each one of its characters with the previous character of the English alphabet. For example, 'b' is converted to 'a', and 'a' is converted to 'z'.

Return the lexicographically smallest string you can obtain after performing the above operation exactly once.

A substring is a contiguous sequence of characters in a string.

A string x is lexicographically smaller than a string y of the same length if x[i] comes before y[i] in alphabetic order for the first position i such that x[i] != y[i].

 

Example 1:

Input: s = "cbabc"
Output: "baabc"
Explanation: We apply the operation on the substring starting at index 0, and ending at index 1 inclusive. 
It can be proven that the resulting string is the lexicographically smallest. 

Example 2:

Input: s = "acbbc"
Output: "abaab"
Explanation: We apply the operation on the substring starting at index 1, and ending at index 4 inclusive. 
It can be proven that the resulting string is the lexicographically smallest. 

Example 3:

Input: s = "leetcode"
Output: "kddsbncd"
Explanation: We apply the operation on the entire string. 
It can be proven that the resulting string is the lexicographically smallest. 

 

Constraints:

  • 1 <= s.length <= 3 * 105
  • s consists of lowercase English letters

代码结果

运行时间: 96 ms, 内存: 18.7 MB


/*
题目思路:
1. 使用Java Stream API来实现相同的逻辑。
2. 我们需要找到第一个不是 'a' 的字符,并将它及其后连续的不是 'a' 的字符替换为前一个字符。
*/

import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Solution {
    public String smallestString(String s) {
        int n = s.length();
        int firstNonA = IntStream.range(0, n).filter(i -> s.charAt(i) != 'a').findFirst().orElse(-1);
        if (firstNonA == -1) return s;
        return IntStream.range(0, n)
                .mapToObj(i -> i >= firstNonA && s.charAt(i) != 'a' ? String.valueOf((char) (s.charAt(i) - 1)) : String.valueOf(s.charAt(i)))
                .collect(Collectors.joining());
    }
}

解释

方法:

本题解采用贪心策略,从左到右扫描字符串。首先,如果字符串全是相同的字符且不是'a',那么直接将整个字符串的每个字符替换为前一个字符。如果字符串中有'a',则从第一个非'a'字符开始,将后续连续的非'a'字符都替换为前一个字符,直到遇到下一个'a'或字符串结束。这样做是因为,按照字典序,'a'是最小的字符,所以尽可能保留'a',而将其他字符替换为前一个字符可以使得整个字符串字典序更小。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在算法中,为什么要区分字符串全是'a'的情况和包含非'a'字符的情况?这种区分对结果有什么影响?
在算法中区分这两种情况主要是因为'a'是字母表中字典序最小的字符。如果字符串全是'a',那么它已经是字典序最小的状态,无需进行任何改动。对于包含非'a'字符的情况,算法的目标是通过变更这些字符来尽可能接近全'a'的状态,从而达到字典序最小。如果不进行这种区分,我们可能会不必要地对全'a'的字符串进行处理,从而使其字典序变大,这显然是不合理的。
🦆
如果字符串中的第一个非'a'字符位于字符串末尾,算法是否仍然有效,会有什么特殊处理?
如果第一个非'a'字符位于字符串末尾,算法仍然有效,且处理逻辑并不特殊。这个字符会被替换为其前一个字符,如'b'会变为'a'。这种处理确保即使非'a'字符位于末尾,也能够通过替换达到更小的字典序。
🦆
在处理连续的非'a'字符时,你选择直接替换为前一个字符,请问这样的处理是否总是能得到字典序最小的字符串?
直接将非'a'字符替换为其前一个字符在大多数情况下能得到字典序较小的字符串,但这不一定总是最小的。特别是当连续非'a'字符跨越多个字母时,简单地替换成前一个字符可能不会得到全局最小的字典序。一个更精确的处理可能需要考虑整体字符串的组合以及更复杂的替换策略。但在多数实际应用中,此方法足够近似实现目标。
🦆
如果输入字符串已经是字典序最小,即全为'a',你的方法会返回什么结果?这是否是预期的输出?
如果输入的字符串已经全为'a',根据算法的逻辑,它会直接返回原始字符串,因为它检测到字符串全为'a'时,会认为没有必要进行任何修改。这是预期的输出,因为全'a'的字符串已经是字典序最小的可能状态。

相关问题