Given a string s
, return the last substring of s
in lexicographical order.
Example 1:
Input: "abab" Output: "bab" Explanation: The substrings are ["a", "ab", "aba", "abab", "b", "ba", "bab"]. The lexicographically maximum substring is "bab".
Example 2:
Input: "leetcode" Output: "tcode"
Note:
1 <= s.length <= 4 * 10^5
- s contains only lowercase English letters.
解题思路:
因为s.substr(i , j) 的字典序一定小于s.substr(i);所以问题转换成求s.substr(i)(0 <= i < len)的字典序最大的字符串;一共有n个子串,如果每个字符串都比较找出字典序最大的字符串则时间复杂度为O(n^2),一定会超时。因为两个字符串比较的时间为O(n),可以通过将字符串比较的时间降为O(1),这样时间复杂度就为O(n).
将字符串比较时间降为O(1): 我想用旋转哈希表来做,求每个字符串的哈希值 ;通过旋转哈希表,可以使求每个字符串的哈希值的时间复杂度降为O(1); 将每个子字符串后缀添'a'使其长度与s的长度一样长,求其哈希值,哈希值最大的那个子字符串就是字字典序最大的字符串;看起来没什么问题,但是s的长度可达到10^5, 那么每个子字符串的哈希值会大到无法想象,解决办法是取模,但是取模之后就无法保证哈希值最大的子字符串就是子字典序最大的字符串了;
class Solution {
public:
string lastSubstring(string s)
{
if(s.empty()) return "" ;
int modl = 1000000007 , len = s.size();
long base = 1 ;
for(int i = 1 ; i < len ; i++) base = (base * 26) % modl;
map<int , vector<int>> hash_poses ;
long prev_hash = 0 ;
for(int i = len - 1 ; i >= 0 ; i--)
{
int hash = (prev_hash / 26 + ((s[i] - 'a') * base) % modl ) % modl;
hash_poses[hash].push_back(i) ;
prev_hash = hash ;
}
auto iter_max_hash = prev(hash_poses.end() , 1) ;
vector<int>& poses = iter_max_hash->second ;
string res = s.substr(poses[0]) ;
for(int i = 1 ; i < poses.size() ; i++)
{
string tmp = s.substr(poses[i]) ;
if(strcmp(tmp.c_str() , res.c_str()) > 0)
res = tmp ;
}
return res ;
}
};
方法二:
从头遍历s,如果s[index] > s[max_index],那么以s[index]开头的字符串字典序一定大于以s[max_index]开头的字符串;
如果s[index] == s[max_index]
//记录index , max_index
int begin_index = index , max_pos = max_index ;
//使index和max_pos继续后移
while(index < len && max_pos < begin_index && s[index] == s[max_pos])
{
index++ ;
max_pos++;
}
增加max_pos < begin_index条件的原因是:
如果max_pos == begin_index,说明s.substr(max_index) 和 s.substr(begin_index)有相同的长度为(begin_index - max_index)的前缀,设其相同前缀为x,剩余的字符串为y; 那么s.substr(max_index) = x + x + y , s.substr(begin_index) = x + y ; 如果 x < y , 那么 x + x +y < x + y < y , 字典序最大的字符串为y ; 如果 x > y , 那么 x + x + y > x + y > y , 字典序最大的字符串为x +x +y ; 所以只要使 x 和 y 比较就好了 , 也就是使s[max_index] 和 s[index]比较 ;
class Solution {
public:
string lastSubstring(string s)
{
int max_index = 0 , index = 1 , len = s.size() ;
while(index < len)
{
if(s[index] > s[max_index])
{
max_index = index;
index++ ;
}
else if(s[index] == s[max_index])
{
int begin_index = index , max_pos = max_index ;
while(index < len && max_pos < begin_index && s[index] == s[max_pos])
{
index++ ;
max_pos++ ;
}
if(index >= len || max_pos >= begin_index) continue ;
if(s[index] > s[max_pos])
max_index = begin_index ;
}
else index++ ;
}
return s.substr(max_index) ;
}
};