按字典序排在最后的子串

Posted 929code

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了按字典序排在最后的子串相关的知识,希望对你有一定的参考价值。

给你一个字符串 s ,找出它的所有子串并按字典序排列,返回排在最后的那个子串

1. 暴力截取比较(超时)

记录最大字符位置,暴力截取比较
class Solution 
public:
    string lastSubstring(string s) 
        map<char, vector<int>> m;
        char mx = \'a\';
        for(int i=0;i<s.size();i++)
            if(s[i]>mx) mx = s[i];
            m[s[i]].push_back(i);
        
        if(mx==\'a\') return s;
        string res = "";
        for(int i=0;i<m[mx].size();i++)
            string cur = s.substr(m[mx][i]);
            if(cur>res) res = cur;
        
        return res;
    
;

2. 双队列逐位比较(超时)

暴力截取的优化,重复筛选当前位置,下一位置
class Solution 
public:
    string lastSubstring(string s) 
        int n = s.size();
        map<char, queue<int>> m;
        char mx = \'a\';
        for(int i=0;i<n;i++)
            if(s[i]>mx) mx = s[i];
            m[s[i]].push(i);
        
        if(mx==\'a\') return s;
        queue<int> & filter1 = m[mx];
        queue<int> filter2;
        int index = -1;//找最后的index
        int times = 0;
        while(filter1.size()!=1)
            int n1 = filter1.size();
            mx = \'a\';
            for(int i=0;i<n1;i++)//第一次筛选下一位置
                int idx = filter1.front();
                filter1.pop();
                if(idx+1==n) continue;
                if(s[idx+1]>mx) mx = s[idx+1];
                filter2.push(idx+1);
            
            int n2 = filter2.size();
            for(int i=0;i<n2;i++)//把当前最大值的坐标还回去
                int idx = filter2.front();
                filter2.pop();
                if(s[idx]==mx) filter1.push(idx);
            
            times++;
        
        return s.substr(filter1.front()-times);
    
;

3. 双指针

比较失效后,可以直接跳过比较过的位置

class Solution 
public:
    string lastSubstring(string s) 
        int left = 0, right = 1, n = s.size();//双指针
        while (right < n) 
            int step = 0;//当前比较轮次
            while (right + step < n && s[left + step] == s[right + step]) 
                step++;//相等后移比较
            if (right + step < n && s[left + step] < s[right + step]) //如果是左边的小
                int t = left;
                left = right;//左指针移动到右指针位置
                right = max(right + 1, t + step + 1);//右指针移动到比较失效的下一位
            
             else  right = right + step + 1;//右指针移动到比较失效的下一位
            
        
        return s.substr(left);
    
;

按字典序排在最后的子串 java实现

按字典序排在最后的子串

给你一个字符串 s,找出它的所有子串并按字典序排列,返回排在最后的那个子串。
输入:“abab”
输出:“bab”
解释:我们可以找出 7 个子串 [“a”, “ab”, “aba”, “abab”, “b”, “ba”, “bab”]。按字典序排在最后的子串是 “bab”。
输入:“leetcode”
输出:“tcode”
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/last-substring-in-lexicographical-order
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • java实现

代码看着复杂其实很简单,只是求解过程要考虑很多情况而以

class Solution 
    public String lastSubstring(String s) 
       int length = s.length();
        if (length == 1) 
            return s;
        
        char[] charArray = s.toCharArray();
        int startIndex = 0;
        int endIndex = 1;

        while (endIndex < length)  // 滑动窗口末端
            if (charArray[startIndex] < charArray[endIndex])  // 1. 遇到比起始字符大的字符时,窗口整体跳到较大字符处
                startIndex = endIndex;
                endIndex++;
             else if (charArray[startIndex] > charArray[endIndex])  // 2.后续字符小于起始字符时,窗口末端右移
                endIndex++;
             else  // 3.遇到相等的字符时,分别从两个下标开始对比两个子串
                int tempIndex = 1; // 临时增量
                while (endIndex + tempIndex < length)  // 子串滑动窗口末端
                    if (charArray[startIndex] < charArray[endIndex + tempIndex])  // 子串出现较大字符
                        startIndex = endIndex + tempIndex;
                        endIndex = endIndex + tempIndex;
                        break;
                    
                    if (charArray[startIndex + tempIndex] < charArray[endIndex + tempIndex])  // 3.1第二子串较大,窗口起始点跳到第二子串起始处
                        startIndex = endIndex;
                        break;
                    
                    if (charArray[startIndex + tempIndex] > charArray[endIndex + tempIndex])  // 3.2第一子串较大,第一子串窗口末端扩到第二子串末端
                        endIndex = endIndex + tempIndex;
                        break;
                    
                    if (charArray[startIndex + tempIndex] == charArray[endIndex + tempIndex])  // 3.3俩当前子串相等,继续对比俩子串
                        tempIndex++;
                    
                    if (endIndex + tempIndex >= length)  // 3.4第二子串窗口末端到顶部,说明未找到比第一子串大的字符,同3.2,结束对比
                        endIndex = endIndex + tempIndex;
                        break;
                    
                
                endIndex++;
            
        
        return s.substring(startIndex);
    

  • python实现
class Solution:
    def lastSubstring(self, s: str) -> str:
        # 排序最后的字符串必然是从某个位置一直到字符串结束
        # 排序最后的字符串必然是以最大字符开始
        mx = max(s) #取最大的字符
        res = ''
        for i, c in enumerate(s):
            #关键是能比较两个字符串
            if c == mx and s[i:] > res:
                res = s[i:]
        return res

以上是关于按字典序排在最后的子串的主要内容,如果未能解决你的问题,请参考以下文章

按字典序排在最后的子串 java实现

按字典序排在最后的子串 java实现

按字典序排在最后的子串 java实现

按字典序排在最后的子串

POJ-3693/HDU-2459 Maximum repetition substring 最多重复次数的子串(需要输出具体子串,按字典序)

RQNOJ 429 词链:单调栈