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

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

相关推荐
可乐加.糖12 分钟前
一篇关于Netty相关的梳理总结
java·后端·网络协议·netty·信息与通信
s91236010114 分钟前
rust 同时处理多个异步任务
java·数据库·rust
9号达人15 分钟前
java9新特性详解与实践
java·后端·面试
cg501719 分钟前
Spring Boot 的配置文件
java·linux·spring boot
啊喜拔牙26 分钟前
1. hadoop 集群的常用命令
java·大数据·开发语言·python·scala
anlogic1 小时前
Java基础 4.3
java·开发语言
非ban必选1 小时前
spring-ai-alibaba第七章阿里dashscope集成RedisChatMemory实现对话记忆
java·后端·spring
A旧城以西2 小时前
数据结构(JAVA)单向,双向链表
java·开发语言·数据结构·学习·链表·intellij-idea·idea
杉之2 小时前
选择排序笔记
java·算法·排序算法
Naive_72 小时前
蓝桥杯准备(前缀和差分)
java·职场和发展·蓝桥杯