算法题解记录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的一些知识。

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

相关推荐
paopaokaka_luck几秒前
基于Spring Boot+Vue的多媒体素材管理系统的设计与实现
java·数据库·vue.js·spring boot·后端·算法
guoruijun_2012_48 分钟前
fastadmin多个表crud连表操作步骤
android·java·开发语言
Hello-Brand18 分钟前
Java核心知识体系10-线程管理
java·高并发·多线程·并发·多线程模型·线程管理
乐悠小码24 分钟前
数据结构------队列(Java语言描述)
java·开发语言·数据结构·链表·队列
史努比.26 分钟前
Pod控制器
java·开发语言
2的n次方_28 分钟前
二维费用背包问题
java·算法·动态规划
皮皮林55129 分钟前
警惕!List.of() vs Arrays.asList():这些隐藏差异可能让你的代码崩溃!
java
莳光.29 分钟前
122、java的LambdaQueryWapper的条件拼接实现数据sql中and (column1 =1 or column1 is null)
java·mybatis
程序猿麦小七34 分钟前
基于springboot的景区网页设计与实现
java·spring boot·后端·旅游·景区
weisian15140 分钟前
认证鉴权框架SpringSecurity-2--重点组件和过滤器链篇
java·安全