题目链接
给你一个字符串 s
,找出它的所有子串并按字典序排列,返回排在最后的那个子串。
s.length
<= 4 * 1 0 5 10^5 105s
仅含有小写英文字符。最关键的是处理时间复杂度,怎么让他小于 O ( n 2 ) O(n^2) O(n2)。
双指针法:
/**
* @param {string} s
* @return {string}
*/
var lastSubstring = function (s) {
let i = 0;
let j = 1;
let offset = 0;
while (j + offset < s.length) {
if (s[i + offset] === s[j + offset]) {
offset++;
}
else if (s[i + offset] > s[j + offset]) {
j = j + offset + 1;
offset = 0;
} else {
i = i + offset + 1;
offset = 0;
if (i >= j) {
j = i + 1;
}
}
}
return s.slice(i);
};
分析:
首先我们得清楚:最大字典序的子串一定是后缀子串。
比较两个个子串的字典序是从第一个字符往后比较的,也就是比较他们的前缀。
我们从前往后遍历字符串,设置一个指针i
指向当前前缀首字符,一个指针j
往后面寻找比指针i
指向的前缀大的前缀首字符位置。这个寻找过程也就是比较过程。
该过程会遇到三种情况。
✨1.s[i+offset]===s[j+offset]
相等,我们继续完后寻找,offset++
。
✨2.s[i+offset]
小于,就不是我们需要的元素,j
→j+offset+1
,offset
→0
。往后重新开始选取。
✨3.s[i+offset]>s[j+offset]
大于,我们找到了比指针i
指向的前缀大的前缀(从j
到j+offset
),也就是说指针i
指向的前缀(从i
到i+offset
)可以被忽略了,咱们继续往后面找,i
→i+offset+1
,offste
→0
。i
如果大于了j
,那么j
→i+1
,因为j
的目的是在i
的后面找到比i
指向的前缀大的前缀。如果找到了最后(j+offset>s.length
)都没有找到这样的前缀,那么此时i
指向的前缀对应的后缀子串(s.slice(i)
)就是我们要寻找的最大字典序的子串。