763.划分字母区间
差点掉进坑的思路(不对,别看,自己的记录)
本来想记录每个字母出现的首下标和尾下标,得到一个有24个区间的数组。然后求这个区间数组的独立并集(只有相交才求并集,下次看相交跟并集比)数目,然后在找每个字母出现的首下标和尾下标的时候,企图遍历。。。。。。太夸张了。。。。。还好突然灵光一闪百度了String中某个字符出现的首下标和尾下标的方法,以及String获取某下标的字符的方法。。。。但是遍历得到数组然后再求独立并集数好像和直接求没啥区别,多此一举,因此有了下面的思路。
思路
- 两个标志:一个begin记录当前集合的开始下标,end记录当前集合的结束下标。
- 从第一个字符开始,begin为0,end为其最后出现的下标,开始从第二个字符遍历,如果在begin和end间出现了一个字符,他的最后出现下标>end,就更新end。
- 否则,如果当前下标>end了,证明来到了新的集合,这时把上个区间的长度加到List里,更新begin为当前的i,end为这个字符最后出现的下标。
- 最后,还有一种情况要考虑:当下标来到最后一个字符,存在两种情况①这个字符是新子串的开始,这个子串只有一个字符②这个字符不是新子串的开始 —— 这两种情况都需要将最后的子串长度加到List里,因为
步骤2/3
分别针对这两种情况,但是2
没有加长度到List,3
条件是i>end,但是这种情况i=end。因此这种情况,就直接把最后的子串长度加进去。
代码
class Solution {
public List<Integer> partitionLabels(String s) {
int begin=0;
int end=s.lastIndexOf(s.charAt(0)); //首字母的最后一次出现
List<Integer> numberS = new ArrayList<>(); //list初始化
for (int i = 1; i < s.length(); i++) {
if(i<end&&s.lastIndexOf(s.charAt(i))>end){ //还是老串
end=s.lastIndexOf(s.charAt(i)); //如果区间内有新字符,且其最后一次出现比目前的end更大,end更新
}else if (i>end){ //当开始新的串
numberS.add(end-begin+1);
begin=i;
end=s.lastIndexOf(s.charAt(i));
}
if (i==s.length()-1) //到最后一个元素,不管其时新的串第一个还是他是老的串,都直接输出最后一个结果!!要是没这个就会少一个数
numberS.add(end-begin+1);
}
//如果有交集,求并集,看最终有几个并集。
return numberS;
}
}
技巧
- List初始化:
List<Integer> numberS = new ArrayList<>();
注意new的不是List。 - List添加元素:
numberS.add(end-begin+1);
- 字符串s的某字符第一次出现的下标:
int a=s.indexOf('q');
- 字符串s的某字符最后一次出现的下标:
int b=s.lastIndexOf('q');
- 字符串某个下标的字符:
s.charAt(0)
- 字符串长度:
s.length()
,注意有括号,数组长度没括号。 - 本题中给出返回值为List,自己也要明白对于这种不确定长度的数组,需要首先声明为List,后面根据情况toArray为数组。
- 本题一个begin和一个end,记录的是满足调价子区间的首尾,而一个一个元素步进是在for循环里,begin记录了当前子串的开始,i步进当大于end证明进入新的子串,这时[begin,end]区间内的元素即满足条件的,记录,然后begin更新为当前end,end更新为当前begin处字符最后出现的位置。而且for里的i必须一个一个加,直接跳到end的话漏掉太多。