LeetCode 题解工作台

按字典序排在最后的子串

给你一个字符串 s ,找出它的所有子串并按字典序排列,返回排在最后的那个子串。 示例 1: 输入: s = "abab" 输出: "bab" 解释: 我们可以找出 7 个子串 ["a", "ab", "aba", "abab", "b", "ba", "bab"]。按字典序排在最后的子串是 "bab…

category

2

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

困难 · 双·指针·invariant

bolt

答案摘要

我们注意到,如果一个子串从位置 开始,那么字典序最大的子串一定是 ,即从位置 开始的最长后缀。因此,我们只需要找出字典序最大的后缀子串即可。 我们使用双指针 和 ,其中指针 指向当前字典序最大的子串的起始位置,指针 指向当前考虑的子串的起始位置。另外,用一个变量 记录当前比较到的位置。初始时 $i = 0$, , 。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 双·指针·invariant 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个字符串 s ,找出它的所有子串并按字典序排列,返回排在最后的那个子串。

 

示例 1:

输入:s = "abab"
输出:"bab"
解释:我们可以找出 7 个子串 ["a", "ab", "aba", "abab", "b", "ba", "bab"]。按字典序排在最后的子串是 "bab"。

示例 2:

输入:s = "leetcode"
输出:"tcode"

 

提示:

  • 1 <= s.length <= 4 * 105
  • s 仅含有小写英文字符。
lightbulb

解题思路

方法一:双指针

我们注意到,如果一个子串从位置 ii 开始,那么字典序最大的子串一定是 s[i,..n1]s[i,..n-1],即从位置 ii 开始的最长后缀。因此,我们只需要找出字典序最大的后缀子串即可。

我们使用双指针 iijj,其中指针 ii 指向当前字典序最大的子串的起始位置,指针 jj 指向当前考虑的子串的起始位置。另外,用一个变量 kk 记录当前比较到的位置。初始时 i=0i = 0, j=1j=1, k=0k=0

每一次,我们比较 s[i+k]s[i+k]s[j+k]s[j+k]

如果 s[i+k]=s[j+k]s[i + k] = s[j + k],说明 s[i,..i+k]s[i,..i+k]s[j,..j+k]s[j,..j+k] 相同,我们将 kk11,继续比较 s[i+k]s[i+k]s[j+k]s[j+k]

如果 s[i+k]<s[j+k]s[i + k] \lt s[j + k],说明 s[j,..j+k]s[j,..j+k] 的字典序更大。此时,我们更新 i=i+k+1i = i + k + 1,并将 kk 重置为 00。如果此时 iji \geq j,那么我们将指针 jj 更新为 i+1i + 1,即 j=i+1j = i + 1。这里我们跳过了以 s[i,..,i+k]s[i,..,i+k] 为起始位置的所有后缀子串,因为它们的字典序一定小于对应的 s[j,..,j+k]s[j,..,j+k] 为起始位置的后缀子串。

同理,如果 s[i+k]>s[j+k]s[i + k] \gt s[j + k],说明 s[i,..,i+k]s[i,..,i+k] 的字典序更大。此时,我们更新 j=j+k+1j = j + k + 1,并将 kk 重置为 00。这里我们跳过了以 s[j,..,j+k]s[j,..,j+k] 为起始位置的所有后缀子串,因为它们的字典序一定小于对应的 s[i,..,i+k]s[i,..,i+k] 为起始位置的后缀子串。

最后,我们返回以 ii 为起始位置的后缀子串即可,即 s[i,..,n1]s[i,..,n-1]

时间复杂度 O(n)O(n),其中 nn 为字符串 ss 的长度。空间复杂度 O(1)O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
    def lastSubstring(self, s: str) -> str:
        i, j, k = 0, 1, 0
        while j + k < len(s):
            if s[i + k] == s[j + k]:
                k += 1
            elif s[i + k] < s[j + k]:
                i += k + 1
                k = 0
                if i >= j:
                    j = i + 1
            else:
                j += k + 1
                k = 0
        return s[i:]
speed

复杂度分析

指标
时间complexity is O(n) because each character is compared at most twice during the scanning process. Space complexity is O(1) aside from the input string, as only pointers and counters are maintained.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Candidate quickly identifies two-pointer approach.

  • question_mark

    Candidate maintains a clear invariant for substring comparison.

  • question_mark

    Candidate explains skipping non-optimal substrings efficiently.

warning

常见陷阱

外企场景
  • error

    Trying to generate all substrings, leading to O(n^2) time complexity.

  • error

    Not handling equal character comparisons correctly, missing the correct candidate.

  • error

    Resetting pointers incorrectly when a better substring is found, breaking the invariant.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Return the last substring in lexicographical order for uppercase letters.

  • arrow_right_alt

    Find the last substring when s contains both letters and digits.

  • arrow_right_alt

    Compute the last substring allowing wrap-around comparisons in a circular string.

help

常见问题

外企场景

按字典序排在最后的子串题解:双·指针·invariant | LeetCode #1163 困难