Last Substring in Lexicographical Order

hard two pointers string suffix

Problem

Given a string s, return the last substring of s when all of its substrings are sorted in lexicographical order. The answer is always a suffix of s, since any substring is a prefix of some suffix and the lexicographically largest one cannot be cut short.

Inputs = "abab"
Output"bab"
Among all substrings, sorting them gives "a", "ab", "aba", "abab", "b", "ba", "bab". The last one is "bab".

def last_substring(s):
    i, j, k = 0, 1, 0
    n = len(s)
    while j + k < n:
        if s[i + k] == s[j + k]:
            k += 1
        elif s[i + k] < s[j + k]:
            i = max(i + k + 1, j)
            j = i + 1
            k = 0
        else:
            j = j + k + 1
            k = 0
    return s[i:]
function lastSubstring(s) {
  let i = 0, j = 1, k = 0;
  const n = s.length;
  while (j + k < n) {
    if (s[i + k] === s[j + k]) {
      k++;
    } else if (s[i + k] < s[j + k]) {
      i = Math.max(i + k + 1, j);
      j = i + 1;
      k = 0;
    } else {
      j = j + k + 1;
      k = 0;
    }
  }
  return s.slice(i);
}
class Solution {
    public String lastSubstring(String s) {
        int i = 0, j = 1, k = 0, n = s.length();
        while (j + k < n) {
            char a = s.charAt(i + k), b = s.charAt(j + k);
            if (a == b) {
                k++;
            } else if (a < b) {
                i = Math.max(i + k + 1, j);
                j = i + 1;
                k = 0;
            } else {
                j = j + k + 1;
                k = 0;
            }
        }
        return s.substring(i);
    }
}
string lastSubstring(string s) {
    int i = 0, j = 1, k = 0, n = s.size();
    while (j + k < n) {
        if (s[i + k] == s[j + k]) {
            k++;
        } else if (s[i + k] < s[j + k]) {
            i = max(i + k + 1, j);
            j = i + 1;
            k = 0;
        } else {
            j = j + k + 1;
            k = 0;
        }
    }
    return s.substr(i);
}
Time: O(n) Space: O(1)