1163. 按字典序排在最后的子串

发布时间 2023-04-24 21:59:59作者: lixycc

题目链接:1163. 按字典序排在最后的子串

方法:双指针

解题思路

【正常走路我不走,就是跳,就是玩】

  • 任何非后缀子串字典序都小于其相应的后缀子串,如 \(s[i, i + k] < s[i, n - 1]\), \(k < n - 1\),故答案一定为后缀子串,即 \(s[i, n - 1]\)
  • 观察数据规模,\(4 * 10^5\),暴力一定超时;
  • 法宝:双指针
    • 指针 \(i\) :指向以当前可能为答案的后缀子串的开头;
    • 指针 \(j\) :指向下一个可能为答案的后缀子串的开头;
    • 同时给两个指针加上相同的偏移量 \(k\)(每次初始为 \(0\)) ,直到所指向的字符 \(s[i + k] != s[j + k]\),因为当 \(s[i, i + k] == s[j, j + k]\) 时,由于 \(i\) 在前,答案一定不会是 \(j\) 开头后缀子串;
    • \(s[i + k] < s[j + k]\) ,说明 \(s[i, i + k] < s[j, j + k]\)
      • 此时 \([i, i + k]\) 区间的字符一定不会为答案的后缀子串的开头,因为 \(s[i + m, i + k] < s[j + m, j + k]\),那么就跳过这段非答案数组,\(i += k + 1\)
      • 若此时 \(i >= j\),即 \([i, i + k + 1]\) 覆盖了 \(j\),那么应该将 \(j = i + 1\),指向 \(i\) 的下一个继续比较;
    • \(s[i + k] > s[j + k]\),说明 \(s[i, i + k] > s[j, j + k]\)
      • 此时 \([j, j + k]\) 区间的字符一定不会为答案的后缀子串的开头,因为 \(s[j + m, j + k] < s[i + m, i + k]\),那么就跳过这段非答案数组,\(j += k + 1\)

代码

class Solution {
public:
    string lastSubstring(string s) {
        int i = 0, j = 1, n = s.length();
        while (j < n) {
            int k = 0;
            while (j + k < n && s[i + k] == s[j + k]) k ++ ;
            if (j + k < n && s[i + k] < s[j + k]) {
                i += k + 1;
                if (i >= j) j = i + 1;
            } else {
                j += k + 1;
            }
        }
        return s.substr(i);
    }
};

复杂度分析

时间复杂度:\(O(n)\)
空间复杂度:\(O(1)\)