763. 划分字母区间
题目:
思路:
【0】依据题目可得两个条件
1)同一个字母的必须在一个片段内
2)将所有划分结果按顺序连接,得到的字符串仍然是 s (也就是位置顺序不能变)
【1】利用数量个数来进行贪心
【2】利用下标位置来进行贪心
代码展示:
【1】利用数量个数来进行贪心
//时间1 ms 击败 100% //内存40.1 MB 击败 60.1% class Solution { // 利用数量个数的方式来进行分割(有点儿类似贪心的思维) public List<Integer> partitionLabels(String s) { int[] count = new int[26]; char[] data = s.toCharArray(); for (char c : data){ count[c - 'a']++; } List<Integer> res = new ArrayList<>(); int curCount = 0 , part = 0; // 如果是想要取出片段字符串的话可以用buf来作为临时存储 , // 如果只为了数量的话就用上面的 part 临时变量即可 // StringBuilder buf = new StringBuilder(); for (int i = data.length-1; i >= 0 ; i--){ // 获取当前字符 char c = data[i]; // 如果当前字符是没有取出来过的 if (count[c - 'a'] > 0){ // 拿出它的个数加入到需要填充的数量中 curCount += count[c - 'a']; // 将记录的个数置为0,表示已经取出来过 count[c - 'a'] = 0; } // 需要填充的数据-1 // buf.insert(0,c); part++; curCount--; // 表示填充进去的数据在前面的片段中不会出现了,这时候可以作为一个分割节点 if (curCount == 0 || i == 0){ // System.out.println(buf.toString() + " 个数:"+buf.length()); // 进行重置临沭存储地址 // buf = new StringBuilder(); res.add(0,part); part = 0; } } return res; } }
【2】利用下标位置来进行贪心
//时间3 ms 击败 74.70% //内存39.8 MB 击败 95.16% //时间复杂度:O(n),其中 n 是字符串的长度。 //需要遍历字符串两次,第一次遍历时记录每个字母最后一次出现的下标位置,第二次遍历时进行字符串的划分。 //空间复杂度:O(1)。这道题中,字符串只包含小写字母,因此 O(26) = O(1)。 class Solution { /** * 利用下标来作为贪心的记录 * 如填入 s = "ababcbacadefegdehijhklij"; * 那么 last = [8, 5, 7, 14, 15, 11, 13, 19, 22, 23, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] * last 明显是记录每个字符出现的最后位置 * 依据条件 同一个字符需要在同一个片段 ,那么为了保证a都在同一片段所以最小的片段大小就是要到下标为8的地方 * 同理 如果在这个过程中 b 也纳入片段 则会同步刷新 片段大小的最大下标 * @param s * @return */ public List<Integer> partitionLabels(String s) { int[] last = new int[26]; int length = s.length(); for (int i = 0; i < length; i++) { last[s.charAt(i) - 'a'] = i; } List<Integer> partition = new ArrayList<Integer>(); int start = 0, end = 0; for (int i = 0; i < length; i++) { end = Math.max(end, last[s.charAt(i) - 'a']); if (i == end) { partition.add(end - start + 1); start = end + 1; } } return partition; } }