算法题解记录12+++划分字母区间(百日筑基)

本题我首先分享我的思路,再在补充中说明贪心算法。

题目描述:

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s

返回一个表示每个字符串片段的长度的列表。

示例 1:

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

示例 2:

复制代码
输入:s = "eccbbbbdec"
输出:[10]

提示:

  • 1 <= s.length <= 500
  • s 仅由小写英文字母组成

解题准备:

1.了解可能存在的基础操作:首先,要求划分字符串,那么划分得到的字符串(就题意,不要求真正出新字符串,并返回),需要进行记录,所以可能有添加;;;其次,既然涉及数组,所以大概率涉及遍历(即查找);;;总之,可能有添加、查找两个基本操作。

2.了解字符串:字符串的本质是字符数组,对字符串的操作归根结底是对字符数组的操作,因此需要知道字符串转字符数组:str.toCharArray();

3.理顺题目要求:题目其实有三个要求:第一,划分得到的字符串段如S1、S2......SN,必须有S1+S2+......+SN==原字符串(不能缺、不能多、顺序不能乱变) === 第二,要求Si与Sj(i,j属于1到N,并且i!=j)之间,不能有相同字符,比如Si是"abcd"有字符a,Sj如果是"aef"则不满足,因为同样有字符'a' === 第三,要求划分后,字符串段尽可能多。

4.模拟操作:去掉所有条件,从原始开始组合,第一个条件,比较基础,第二个条件,引出以下疑问:如果我们只要求,划分出两个字符串段S1和S2,要求S1和S2中没有相同字符,怎么做?

解题难点1分析:

难点1:

在解题准备"4"中,如果只要求,划分两个字符串段S1、S2,且S1和S2中没有相同字符,可以怎么操作?

思路1分析:更简单的角度

如果我们提供两个不同的字符串S1、S2,要求找到S1、S2中是否有相同字符,如果有返回true,没有返回false,怎么做?【S1、S2中只有小写字符】

思路1解:

【思路1的题目用boolean数组即可,因为只判断有没有,本题用int数组是为接下来做准备】

第一,用一个长度为26的int[]数组A1,先遍历一次S1,记录每个字符出现的个数(有这个字符,对应的位置++)。

第二,同理,创建长度为26的int[]数组A2,遍历S2,记录字符个数,如果有对应字符,那么对应位置++。

第三,遍历数组A1,但凡有A1[i]!=0,判断A2[i]==0?如果等于0,继续遍历,不等于0,说明二者有重复,返回false。

思路2分析:从难点1角度出发

对于输入字符串S,如果已经划分为两部分,那么可以用思路1求解,目前问题是要求你划分。

所以,需要动态的变化,动态的记录。【使用一个指针(下标)ptr】

思路2解:

第一步,继续创建长度为26的int数组A1、A2,首先将S的字符记录进A1中。

第二步,移动指针ptr,将第一个字符记录进A2,从A1删除第一个字符(对应字符--)

第三步,通过A1、A2判断是否有重复字符,如果无重复,则将S划分。

(比如S是"abdb"),直接划分成【"a","bcb"】即可。

当然,很可能S是"abdafe"这种类型。

那么,第四步,进行迭代,每次,ptr向前移动一步,将S.charAt(ptr)记录进A2,同时删除A1数据。然后进行第三步判断,

直到1.找到无重复字符。2.遍历完整个字符串S,都没有符合题意。才返回数据。

解题难点2分析:

由"解题难点1分析",我们容易知道如何划分一个字符串S,使S1和S2中没有相同字符,并且使S1尽可能短【因为一旦遇到S1、S2无相同字符,就立刻返回S1,如果从0开始,那么S1一定是最短的】

不过,题目要求划分尽可能多的字符串段。

难点2:

对于一个字符串S,如何划分出尽可能多的、字符不重复的字符串段?

思路1分析:用迭代的思想

我们已经知道从S划分S1、S2,那么对于原始输入S,我们划分出S1、S2后,S1必定和S2无相同字符、并且但凡S1减少一位,就会有相同字符,所以,S1是最基础输出【也一定是第一个输出】。

那么,想找到第二个输出,必然要从S2中找。

不妨把S2看成S,从S2中拿到S1' 和 S2',

拿到第二个输出后,又得考虑S2'中是否存在......

就此迭代......直到遍历完整个字符数组,即可返回完整输出。

迭代结束条件:这里需要考虑指针ptr是否越界,一旦越界必然出错,所以ptr最多指向s.length-1,至此迭代结束。

代码:

class Solution {
    public List<Integer> partitionLabels(String s) {
        int[] temp=new int[26];
        int[] data=new int[26];
        char[] x=s.toCharArray(); // 用s.charAt(i)也一样;
        int ptr=0; // 指针
        List<Integer> res=new ArrayList<>();

        for(char a:x){
            temp[a-'a']++; // 首先记录A1
        }

        
        while(ptr<x.length){  // 只要不遍历结束,就一直遍历
            // 这一部分属于初始化,否则一开始data中为null,必然与temp不相交
            data[x[ptr]-'a']++; // A2++
            temp[x[ptr]-'a']--; // A1--
            ptr++; //ptr++

            while(isFalse(temp, data)){
                data[x[ptr]-'a']++;
                temp[x[ptr]-'a']--;
                ptr++;
            }
            // ttt用于确定前面已划分出的字符串长度
            int ttt=0;
            for(int n:res){
                ttt+=n;
            }
            res.add(ptr-ttt); 
            // 重置A2
            for(int i=0; i<26; i++){
                data[i]=0;
            }
        }

        return res;
    }

    // 判断是否有重复元素
    private boolean isFalse(int[] temp, int[] data){
        for(int i=0; i<26; i++){
            if(data[i]!=0){
                if(temp[i]!=0){
                    return true; // 有重复元素返回true
                }
            }
        }

        return false;
    }
}

补充贪心算法:

本题的题解使用贪心算法,思路也比较简单。

1.利用HashMap哈希表,记录所有字符最晚出现的位置,key是字符,value是Integer,表示最晚的位置。比如"baabcbacadefegdehijhklij",记录a=8, b=5......

2.采用for循环遍历s的字符数组,拿到s.charAt(i)最晚出现的位置(hashMap.get(s.charAt(i)),如果最晚出现晚于目前最晚的位置(比如a=8,b=5,首先遍历到b,记录最晚等于5;然后遍历到a,记录最晚为8......)

3.如果一直遍历到8,没有出现更晚的数据,返回8,这个就是最小的满足题意的答案。

4.解释:第一个是b=5,也就是说,S1起码到5这个位置,否则不可能出现S1、S2没有相交字符。然后是a=8,也就是说,S1至少到8,否则必定有......(选取最大的即可)

以上内容即我想分享的关于力扣热题12的一些知识。

我是蚊子码农,如有补充,欢迎在评论区留言。个人也是初学者,知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

相关推荐
suweijie7683 小时前
SpringCloudAlibaba | Sentinel从基础到进阶
java·大数据·sentinel
公贵买其鹿4 小时前
List深拷贝后,数据还是被串改
java
xlsw_7 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹8 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭8 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫8 小时前
泛型(2)
java
超爱吃士力架8 小时前
邀请逻辑
java·linux·后端
南宫生8 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石8 小时前
12/21java基础
java
李小白669 小时前
Spring MVC(上)
java·spring·mvc