贪心算法 | 763.划分字母区间

·题目描述

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

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

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

示例 1:

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

示例 2:

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

·解题思路

很质朴的想法是,遍历一圈字符串s, 把每个字母出现的起始位置用数组记录下来。再套用之前leetcode 452 用最少数量的箭引爆气球 和 leetcode 435 无重复区间的 思路, 将数组进行规划;

规划分为三步:1.最开始的位置进行排序;2.当后一个数组的开始位置小于前一个数组的结束位置的时候,说明两个数组有重叠,更新数组区间;3.当后一个数组的开始位置大于前一个数组的结束位置的时候,说明两个数组没有重叠区间,需要计算前一个数组的字符串长度

·解题细节:

1.每一个字母都可能出现,因此创建26*2的二维数组,计算每一个出现的字母的开始和结束位置。同时,如何判断该数字是开始坐标还是结束坐标------创建flag数组来标记,若是flag = 0 ,表示之前没有出现过,该坐标为起始坐标,反之则为结束坐标。结束坐标需要不断更新;

            int[][] num = new int[26][2];
            int[] flag = new int[26];

            for(int i = 0; i < s.length(); i++){
            int temp  = s.charAt(i) - 'a';
            if(flag[temp] == 0){num[temp][0] = i;flag[temp] = 1;}
            else{ num[temp][1] = Math.max(num[temp][1], i);}
            }

2.对记录的字母坐标按照第一个元素进行排序

        Arrays.sort(num, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return Integer.compare(o1[0], o2[0]);
            }
        });
        
        #打印结果
        for(int i = 0; i < num.length; i++){
            System.out.println(num[i][0] + " " + num[i][1]);
        }

3.对坐标数组进行处理,遍历num数组,利用栈来辅助更新区间。当当前数组的开始位置小于栈顶数组的结束位置的时候,说明两个数组有重叠,更新数组区间;反之说明两个数组没有重叠区间,需要计算前一个数组的字符串长度

        Stack<int[]> stack = new Stack<int[]>();
        for(int i = 0;i < num.length;i++){
            
 
            
            #当栈为空的时候,先压入
            if(stack.isEmpty()) stack.push(num[i]);
            else{
                int[] point = stack.peek();
                if(num[i][0] < point[1]){
                    int newend = Math.max(point[1], num[i][1]);
                    int[] newpoint = new int[] {point[0],newend};
                    stack.pop();
                    stack.push(newpoint);
                }
                else{
                    int len = stack.peek()[1] - stack.peek()[0] + 1;
                    res.add(len);
 
                    stack.pop();
                    stack.push(num[i]);
                }
            }
        }

4.有可能最后一个子字符串不能满足for循环的收割条件,也就是说栈不为空,这是还需要处理

        while(!stack.isEmpty()){
            int[] point = stack.pop();
            if(point[1] == 0) {res.add(1);count += 1;}
            else{
                int len = point[1] - point[0] + 1;
                res.add(len);
            }
        }

5.处理空数组:

由于给出的字符不一定包含26个字母,也就是说num中有很多空数组参与了排序,这时候只需要在遍历的时候,当数组两个元素都是0的时候,continue即可

if(num[i][0] == 0 && num[i][1] == 0){continue;}

6.处理单个元素

字符串中可能存在单个元素,分为两种情况:头单个【0,0】和其他【x(x!= 0) , 0】

处理头单个的时候,只需要增加一个count技术,当所有子串的长度小于给定字符串的长度时,说明有头单个元素漏加,只需要在列表结构头部增加 1 ,即可

处理其他单个元素的时候,只需要在遍历num时,当数组第一个元素不为0,而第二元素为0 的时候,将第二个元素变为第一个元素相同值即可

            if(num[i][0] == 0 && num[i][1] == 0){continue;}
            if(num[i][0] != 0 &&  num[i][1] == 0){num[i][1] = num[i][0];}

·java代码

import java.util.*;

class Solution {
    public List<Integer> partitionLabels(String s) {
        int[][] num = new int[26][2];
        int[] flag = new int[26];
        int count = 0;

        for(int i = 0; i < s.length(); i++){
            int temp  = s.charAt(i) - 'a';
            if(flag[temp] == 0){num[temp][0] = i;flag[temp] = 1;}
            else{ num[temp][1] = Math.max(num[temp][1], i);}
        }

        Arrays.sort(num, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return Integer.compare(o1[0], o2[0]);
            }
        });

        for(int i = 0; i < num.length; i++){
            System.out.println(num[i][0] + " " + num[i][1]);
        }

        List<Integer> res = new ArrayList<Integer>();
        Stack<int[]> stack = new Stack<int[]>();
        for(int i = 0;i < num.length;i++){
            if(num[i][0] == 0 && num[i][1] == 0){continue;}
            if(num[i][0] != 0 &&  num[i][1] == 0){num[i][1] = num[i][0];}
            if(stack.isEmpty()) stack.push(num[i]);
            else{
                int[] point = stack.peek();
                if(num[i][0] < point[1]){
                    int newend = Math.max(point[1], num[i][1]);
                    int[] newpoint = new int[] {point[0],newend};
                    stack.pop();
                    stack.push(newpoint);
                }
                else{
                    int len = stack.peek()[1] - stack.peek()[0] + 1;
                    res.add(len);
                    count += len;
                    stack.pop();
                    stack.push(num[i]);
                }
            }
        }
        while(!stack.isEmpty()){
            int[] point = stack.pop();
            if(point[1] == 0) {res.add(1);count += 1;}
            else{
                int len = point[1] - point[0] + 1;
                res.add(len);
                count += len;
            }
        }
        if(count < s.length()) res.add(0,1);
        return res;
    }
}

public class Main {
    public static void main(String[] args) {
        Solution solution = new Solution();
        System.out.println(solution.partitionLabels("vhaagbqkaq"));
    }
}
相关推荐
Theodore_10222 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou2 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
冰帝海岸3 小时前
01-spring security认证笔记
java·笔记·spring
世间万物皆对象3 小时前
Spring Boot核心概念:日志管理
java·spring boot·单元测试
没书读了4 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
小二·4 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
懒洋洋大魔王4 小时前
RocketMQ的使⽤
java·rocketmq·java-rocketmq
武子康4 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神5 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式