无重叠区间+火星字典+基本计算器

目录

无重叠区间一leetcode56

无重叠区间二leetcode 435

解题思路一

解题思路二:贪婪法:

解题思路三:按照结束时间排序

火星字典LeetCode269

leetCode772 基本计算器


无重叠区间一leetcode56

如果没有融合,当前区间就变成新的previous,下一个区间成为新的current

  1. 先将所有的区间按照起始时间的先后顺序排序,从头到尾扫描一遍
  2. 定义两个变量 previous 和 current,分别表示前一个区间和当前的区间
  • 如果没有融合,那么当前区间就变成了新的前一个区间,下一个区间成为新的当前区间
  • 如果发生了融合,更新前一个区间的结束时间。

这个就是贪婪算法。

class Solution {
    public int[][] merge(int[][] intervals) {
        //将所有区间按照起始时间的先后顺序排序
    Arrays.sort(intervals, new Comparator<int[]>(){
        public int compare(int[] a, int[] b){
            return a[0] - b[0];
        }
    });

    int[] previous = null;
    List<int[]> result = new ArrayList<>();

    for(int[] current : intervals){
        //如果是第一个区间,或者当前区间和前一个区间没有重叠
        //那么将当前区间加入到结果中
        if(previous == null || current[0] > previous[1]){
            result.add(previous = current);
        }
        //否则,两个区间发生了重叠,更新前一个区间的结束时间
        else{
            previous[1] = Math.max(previous[1], current[1]);
        }
    }
    //把list转换为二维数组的方法
    return result.toArray(new int[result.size()][]);
    }
}

 

无重叠区间二leetcode 435

解题思路一

主体函数中,先将区间按照起始时间的先后顺序排序,然后调用递归函数

递归函数中,先检查所有区间是否处理完,是的话,表明不需要删除操作,直接返回

定义taken与nottaken变量,用来记录:

-如果保留当前区间的话,最少需要删除多少其他区间

-如果删除当前区间的话,最少需要删除多少区间

int eraseOverlapIntervals(int prev, int curr, int[][] intervals){
    if(curr == intervals.length){
        return 0;
    }

    int taken = Integer.MAX_VALUE, notaken;

    if(prev == -1 || intervals[curr][0] >= intervals[prev][1]){
        //只有当prev,curr没有发生重叠的时候,才可以选择保留当前的区间
        taken = eraseOverlapIntervals(curr, curr + 1, intervals);
    }

    //其他情况,可以考虑删除curr区间,看看删除了它之后会不会产生最好的结果
    notaken = eraseOverlapIntervals(prev, curr + 1, intervals) + 1;

    return Math.min(taken, notaken);
}

解题思路二:贪婪法:

将所有的区间按照起始时间的先后顺序排序

定义一个end变量记录当前的最小结束时间点

定义一个count变量记录到目前为止删除了多少区间

从第二个区间开始

判断一下当前区间和前一个区间的结束

如果发现当前区间与前一个区间有重叠

即当前区间的起始时间小于上一个区间的结束时间

则end变量记录下两个结束时间的最小值

意味着把结束时间晚的区间删除,计数加一

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        if(intervals.length == 0){
            return 0;
        }
        Arrays.sort(intervals, new Comparator<int[]>(){
            public int compare(int[] a, int[] b){
                return a[0] - b[0];
            }
        });
        int end = intervals[0][1], count = 0;

        for(int i = 1; i < intervals.length; i++){
        //表示有重叠,end保留最小值
            if(intervals[i][0] < end){
                end = Math.min(end, intervals[i][1]);
                count ++;
            }
            else{
                end = intervals[i][1];
            }
        }
        return count;

    }
}

解题思路三:按照结束时间排序

将所有的区间按照起始时间的先后顺序排序

定义一个end变量记录当前的最小结束时间点

定义一个count变量记录有多少个没有重叠的区间

从第二个区间开始遍历剩下的区间

如果发现当前区间与前一个区间结束时间没有重叠,则计数加一,同时更新一下新的结束时间

最后,用总区间的个数减去没有重叠的区间个数,得到最少要删除的区间个数

int eraseOverlapIntervals(int[][] intervals){
    if(intervals.length == 0){
        return 0;
    }
    Arrays.sort(intervals, new Comparator<int[]>(){
            public int compare(int[] a, int[] b){
                return a[0] - b[0];
            }
    });

    int end = intervals[0][1],
    int count = 1;

    for(int i =  1; i < intervals.length; i++){
        if(intervals[i][0] >= end){
            end = intervals[i][1];
            count ++;
        }
    }

    return intervals.length - count;
}

火星字典LeetCode269

如果组合得到最终的关系呢?利用拓扑排序,得到有向图的一个拓扑排序

 

用深度优先的方法来进行拓扑排序

-visited集合:用来记录已访问过的顶点

-stack堆栈:

    当从某顶点出发,访问完其他所有顶点

    最后才把当前顶点加入到堆栈:即要想把该点加入stack里,必须先把其他跟它有联系的顶点都处理完毕

-loop集合:有效防止有向图中出现环的情况,每一轮访问完,都必须把loop集合清空完,如果不清空的话,会误把非环当成环,而提前终止了程序,无法将其加入堆栈中。

  • 将当前结点u加入visited集合以及loop集合中
  • 逐个访问与顶点u相邻的其他顶点v
  • 如果在此轮访问过程中,v其实早已被访问过,则此处有环出现,返回false
  • 否则,如果顶点v还没有被访问过,就递归地访问它,如果在访问顶点v时发现了环,则返回false
  • 当这一轮访问结束后,即从顶点u出发访问完所有能访问的点,将u从loop集合里删除
  • 把u加入到堆栈中

代码实现

包括两大步骤,第一步是根据输入构建一个有向图;第二步是对这个有向图进行拓扑排序。

String alienOrder(String[] words){
    if(words == null || words.length == 0){
        return null;
    }

    if(words.le == 1){
        return words[0];
    }
    //定义了一个邻接链表adjList,表示有向图也可以使用邻接矩阵
    Map<Character, List<Character>> adjList= new HashMap<>();

    for(int i = 1; i < words.length; i++){
        String w1 = words[i-1];
        String w2 = words[i];

        int len = Math.min(w1.length(), w2.length());

        int diffIndex = 0;
        while((diffIndex < n) && (w1.charAt(diffIndex) == w2.charAt(diffIndex)){
            diffIndex ++;
        }
        //找到了对应的位置应该为 s1.charAt(diffIndex) -> s2.charAt(d)
        //一旦出现两个字母不同,就处理好顶点之间的关系
        if(diffIndex < n){
            char c1 = s1.charAt(diffIndex);
            char c2 = s2.charAt(diffIndex);
            if(!map.containsKey(c1)){
                map.put(c1, new ArrayList<Character>());
            }
            if(!map.containsKey(c2)){
                map.put(c2, new ArrayList<Character>());
            }
            map.get(c1).add(c2);
        }
    }

    Set<Character> visited = new HashSet<>();
    Set<Character> loop = new  HashSet<>();
    Stack<Character> stack = new  Stack<Character>();

    for(Character key : adList.keySet){
        if(!visited.contains(key)){
            if(!topologicalSort(adList, key, visited, loop, stack)){
                return "";
            }
        }
    }

    StringBuilder sb = new StringBuilder();
    while(!stack.isEmpty()){
        sb.append(stack.pop());
    }

    return sb.toString();

}


boolean topologicalSort<Mat<Character, List<Character>> adList, char u, 
    Set<Character> visited, Set<Character> loop, Set<Character> stack){
            visited.add(u);
            loop.add(u);

            if(adList.containsKey(u)){
                for(int i = 0; i < adList.get(u).size(); i++){
                    char v = adList.get(u).get(i);

                    if(loop.contains(v)){
                        return false;
                    }

                    if(!visited.contains(v)){
                        if(!topologicalSort(adList, v, visited, loop, stack)){
                            return false;
                        }
                    }
                }
            }

            loop.remove(u);
            stack.push(u);
            return true;

        }

leetCode772 基本计算器

class Solution {
    public int calculate(String s) {
        Queue<Character> queue = new LinkedList<>();
        for(char c: s.toCharArray()){
            if(c != ' '){
                queue.offer(c);
            }
        }
        queue.add('+');//在末尾额外添加一个+

        return calculate(queue);//在主函数中调用一个递归函数
    }
    public int calculate(Queue<Character>  queue){
        char sign = '+';
        int num = 0;
        //定义一个新变量来记录要被处理的数
        Stack<Integer> stack = new Stack<>();

        while(!queue.isEmpty()){
            char c = queue.poll();
            if(Character.isDigit(c)){
                num = 10 * num + c - '0';
            }
            //如果遇到了符号,表明我们要开始统计一下当前的结果
            else{
                //如果遇到了一个左括号,开始递归调用,求得括号中的计算结果,将它赋值给当前的num
                if(c == '('){
                    num = calculate(queue);
                }
                else {
                    if(sign == '+'){
                        //当遇到加号,把当前的数压入堆栈中
                        stack.push(num);
                    }
                    else if(sign == '-'){
                        //当遇到的是减号,把当前数的相反数压入堆栈中
                        stack.push(-num);
                    }
                    //当遇到的是乘号,把前一个数从堆栈中取出,然后和当前的数相乘,相乘完毕之后再放回堆栈
                    else if(sign == '*'){
                        stack.push(stack.pop() * num);
                    }
                    //当遇到的是除号,把前一个数从堆栈中取出,然后和当前的数相除,相除完毕之后再放回堆栈
                    else if(sign == '/'){
                        stack.push(stack.pop() / num);
                    }
                    //对num清零,并且更新当前符号位
                    num = 0;
                    sign = c;
                    if(c == ')'){
                        break;//当遇到一个右括号时,就可以结束循环,直接返回当前总和
                    }
                }
            }
        }
        int sum = 0;
        //堆栈里存储的都是需要相加的结果,将它们相加,返回总和即可
        while(!stack.isEmpty()){
            sum += stack.pop();
        }
        return sum;
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值