Welcome to Subscribe On Youtube

1163. Last Substring in Lexicographical Order

Description

Given a string s, return the last substring of s in lexicographical order.

 

Example 1:

Input: s = "abab"
Output: "bab"
Explanation: The substrings are ["a", "ab", "aba", "abab", "b", "ba", "bab"]. The lexicographically maximum substring is "bab".

Example 2:

Input: s = "leetcode"
Output: "tcode"

 

Constraints:

  • 1 <= s.length <= 4 * 105
  • s contains only lowercase English letters.

Solutions

Solution 1: Two pointers

We notice that if a substring starts from position $i$, then the largest substring with the largest dictionary order must be $s[i,..n-1]$, which is the longest suffix starting from position $i$. Therefore, we only need to find the largest suffix substring.

We use two pointers $i$ and $j$, where pointer $i$ points to the starting position of the current largest substring with the largest dictionary order, and pointer $j$ points to the starting position of the current substring being considered. In addition, we use a variable $k$ to record the current position being compared. Initially, $i = 0$, $j=1$, $k=0$.

Each time, we compare $s[i+k]$ and $s[j+k]$:

If $s[i + k] = s[j + k]$, it means that $s[i,..i+k]$ and $s[j,..j+k]$ are the same, and we add $k$ by $1$ and continue to compare $s[i+k]$ and $s[j+k]$;

If $s[i + k] \lt s[j + k]$, it means that the dictionary order of $s[j,..j+k]$ is larger. At this time, we update $i = i + k + 1$, and reset $k$ to $0$. If $i \geq j$ at this time, we update pointer $j$ to $i + 1$, that is, $j = i + 1$. Here we skip all suffix substrings with $s[i,..,i+k]$ as the starting position, because their dictionary orders are smaller than the suffix substrings with $s[j,..,j+k]$ as the starting position.

Similarly, if $s[i + k] \gt s[j + k]$, it means that the dictionary order of $s[i,..,i+k]$ is larger. At this time, we update $j = j + k + 1$ and reset $k$ to $0$. Here we skip all suffix substrings with $s[j,..,j+k]$ as the starting position, because their dictionary orders are smaller than the suffix substrings with $s[i,..,i+k]$ as the starting position.

Finally, we return the suffix substring starting from $i$, that is, $s[i,..,n-1]$.

The time complexity is $O(n)$, where $n$ is the length of string $s$. The space complexity is $O(1)$.

  • class Solution {
        public String lastSubstring(String s) {
            int n = s.length();
            int i = 0;
            for (int j = 1, k = 0; j + k < n;) {
                int d = s.charAt(i + k) - s.charAt(j + k);
                if (d == 0) {
                    ++k;
                } else if (d < 0) {
                    i += k + 1;
                    k = 0;
                    if (i >= j) {
                        j = i + 1;
                    }
                } else {
                    j += k + 1;
                    k = 0;
                }
            }
            return s.substring(i);
        }
    }
    
  • class Solution {
    public:
        string lastSubstring(string s) {
            int n = s.size();
            int i = 0;
            for (int j = 1, k = 0; j + k < n;) {
                if (s[i + k] == s[j + k]) {
                    ++k;
                } else if (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.substr(i);
        }
    };
    
  • 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:]
    
    
  • func lastSubstring(s string) string {
    	i, n := 0, len(s)
    	for j, k := 1, 0; j+k < n; {
    		if s[i+k] == s[j+k] {
    			k++
    		} else if 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:]
    }
    
  • function lastSubstring(s: string): string {
        const n = s.length;
        let i = 0;
        for (let j = 1, k = 0; j + k < n; ) {
            if (s[i + k] === s[j + k]) {
                ++k;
            } else if (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.slice(i);
    }
    
    

All Problems

All Solutions