LeetCode 763. 划分字母区间

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40697071/article/details/86672664

题目:763. 划分字母区间

类型:贪心算法

字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段。返回一个表示每个字符串片段的长度的列表。

示例 1:

输入: S = "ababcbacadefegdehijhklij"
输出: [9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。

注意:

  1. S的长度在[1, 500]之间。
  2. S只包含小写字母'a''z'

解题思路:

解法一是我自己的解题思路,时间复杂度为 O(n^2),还是有点高的,在做的时候也想到了用空间换时间的做法,即首先把26个字符的出现的开头和结尾位置进行保存,之后直接通过贪心算法的区间类型题的通用解法就可以了,但觉得代码写起来有点复杂。我的这个思路就是进行两层循环,外层是遍历每个字符,内层是遍历当前字符后面的所有字符,查找和当前字符相同的字符所出现的最右位置,以此来确定区间的结尾。当外层循环也到达最右位置的时候说明已经可以进行分割,记录之后再将开始和结尾变量重新初始化为下一个位置即可。

解法二是实例中的代码,时间复杂度为O(n),但是需要 26 个额外的数组空间用来保存每个字符所出现的最右位置。具体的思路就是先把 26 个字符在字符串中出现的最右位置都进行记录,之后通过循环,从起始的字符开始,起始字符的下标就是开始的位置,它的最右位置就是结束的位置,然后扫描这段区间之内的字符,看看是否需要延长区间来进行兼容。扫描之后再将结束的最右位置减去起始位置保存即可,下一步直接将其实位置加上区间长度即为下一个区间的起始位置。

代码:

//解法一:
    vector<int> partitionLabels(string S) {
        
        int start = 0, end = 0, len = S.length();
        vector<int> res;
        char cur = S[0];
        
        for(int i = 0; i < len; i++){
            cur = S[i];
            //从当前位置的下一位置开始查找当前字符所出现的最远位置
            for(int j = i + 1; j < len; j++)
                if(cur == S[j]) end = max(end, j);
            //如果已经到达可划分的位置
            if(i == end){
                res.push_back(end-start+1);
                //如果不是最后一个元素则 start 和 end 同时初始化为当前结尾的下一个位置
                if(i != len-1) {
                    start = ++end;
                }
            }
        }
        
        return res;
    }


//解法二:
    int divide(string S,int start,int end,int letterRight[26]){
        int left,right;
        left=start;
        //保存当前字符的最右位置
        right=letterRight[S[left]-'a'];
        //确定当前字符串区间是否可以进一步延长
        for(int i=left+1;i<=right;i++){
            //检查是否需要延长区间
            if(letterRight[S[i]-'a']>right) right=letterRight[S[i]-'a'];
        }
        //返回当前划分字符串的长度
        return right-left+1;
    }
    vector<int> partitionLabels(string S) {
        //数组用来记录每个字符所出现的最右位置
        int letterRight[26];
        vector<int> result;
        //初始化记录数组
        for(int i=0;i<26;i++){
            int t=S.find_last_of((char)(i+'a'));
            letterRight[i]=t;
        }
        int start=0;
        int end=S.size();
        int tmp;
        //进行字符串的划分
        while(start<end){
            //返回的是当前划分区间的字符串长度
            tmp=divide(S,start,end,letterRight);
            result.push_back(tmp);
            //start 初始化为下一段字符串的起始位置
            start+=tmp;
        }
        return result;
    }

猜你喜欢

转载自blog.csdn.net/qq_40697071/article/details/86672664