2024-02-08(贪心算法:区间问题、哈夫曼树)

文章介绍了在AcWing题库中涉及的四个区间问题,包括区间选点、最大不相交区间数量、区间分组和区间覆盖,都采用贪心策略,通过排序和枚举操作找出最优解。
摘要由CSDN通过智能技术生成

算法基础课贪心部分每道题贪心策略的证明汇总 - AcWing 

1.区间问题

905. 区间选点 - AcWing题库

1.将每个区间按右端点从小到大排序

2.从前往后依次枚举每个区间,如果当前区间中已经包含点,则直接pass,否则,选择当前区间的右端点

使每一个选出来的右端点尽可能的占更多的空间

import java.util.*;

class Range implements Comparable<Range>{//定义一个新的结构体
    int l, r;
    public Range(int l, int r){
        this.l = l;
        this.r = r;
    }
    public int compareTo(Range o){
        return Integer.compare(r, o.r);//根据右端点的大小排序
    }
}

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int N = 100010;
        int INF = 0x3f3f3f3f;
        Range[] range = new Range[N];//定义一个结构体类型的数组
        
        int n = sc.nextInt();
        for(int i = 0; i < n; i ++){
            int l = sc.nextInt();
            int r = sc.nextInt();
            range[i] = new Range(l, r);
        }
        
        Arrays.sort(range, 0, n);//排序
        
        int res = 0;//共需要多少个点
        int ed = -INF;//表示上一个区间的右端点
        for(int i = 0; i < n; i ++){
            if(ed < range[i].l){
                res ++;
                ed = range[i].r;
            }
        }
        System.out.print(res);
    }
}

 

908. 最大不相交区间数量 - AcWing题库 

1.将每个区间按右端点从小到大排序

2.从前往后依次枚举每个区间,如果当前区间中已经包含点,则直接pass,否则,选择当前区间的右端点

除了问法不一样,和上一题本质上是一样的 

 

import java.util.*;

//和上一题的代码一样
class Range implements Comparable<Range>{
    int l, r;
    public Range(int l, int r){
        this.r = r;
        this.l = l;
    }
    public int compareTo(Range o){
        return Integer.compare(r, o.r);
    }
}

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int N = 100010, INF = 0x3f3f3f3f;
        Range[] range = new Range[N];
        
        int n = sc.nextInt();
        for(int i = 0; i < n; i ++){
            int l = sc.nextInt();
            int r = sc.nextInt();
            range[i] = new Range(l, r);
        }
        
        Arrays.sort(range, 0, n);
        
        int res = 0;
        int ed = -INF;
        for(int i = 0; i < n; i ++){
            if(ed < range[i].l){
                res ++;
                ed = range[i].r;
            }
        }
        System.out.print(res);
    }
}

 

906. 区间分组 - AcWing题库 

 1.将每个区间按左端点从小到大排序

 2.从前往后处理每个区间,判断能否将其放到某个现有的组中(L[i] > Max_r)

       如果不存在这样的组,则开新组,将其放进去

       如果存在这样的组,将其放进去,并更新当前组的Max_r

import java.util.*;

class Range implements Comparable<Range>{
    int l, r;
    public Range(int l, int r){
        this.l = l;
        this.r = r;
    }
    public int compareTo(Range o){
        return Integer.compare(l, o.l);
    }
}

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int N = 100010;
        Range[] range = new Range[N];
        
        int n = sc.nextInt();
        for(int i = 0; i < n; i ++){
            int l = sc.nextInt();
            int r = sc.nextInt();
            range[i] = new Range(l, r);
        }
        
        Arrays.sort(range, 0, n);//根据左端点排序
        
        Queue<Integer> heap = new PriorityQueue<>();//小根堆
        
        for(int i = 0; i < n; i ++){
            if(heap.isEmpty() || range[i].l <= heap.peek()) heap.add(range[i].r);//建立一个新的组
            else{
                heap.poll();
                heap.add(range[i].r);
            }
        }
        System.out.print(heap.size());
    }
}

 907. 区间覆盖 - AcWing题库 

 1.将所有区间按照左端点从小到大排序

 2.从前往后依次枚举每个区间,在所有能覆盖start的区间中,选择右端点最长的,并将start更新为右端点的最大值

import java.util.*;

class Range implements Comparable<Range>{
    int l, r;
    public Range(int l, int r){
        this.l = l;
        this.r = r;
    }
    public int compareTo(Range o){
        return Integer.compare(l, o.l);
    }
}

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int st = sc.nextInt();
        int ed = sc.nextInt();
        int n = sc.nextInt();
        int N = 100010;
        Range[] range = new Range[N];
        
        for(int i = 0; i < n; i ++){
            int l = sc.nextInt();
            int r = sc.nextInt();
            range[i] = new Range(l, r);
        }
        
        Arrays.sort(range, 0, n);
        
        int res = 0;
        boolean flag = false;
        for(int i = 0; i < n; i ++){
            int j = i;
            int r = -0x3f3f3f3f;
            while(j < n && range[j].l <= st){//一定要注意条件的顺序问题
                r = Math.max(r, range[j].r);//找到覆盖st的区间中右端点最长的
                j ++;
            }
            if(r < st){//如果循环到最后都没能超过st,则res=-1
                res = -1;
                break;
            }
            res ++;//否则区间数量加1
            
            if(r >= ed){
                flag = true;//如果最右端点已经超过ed,那么就直接结束循环
                break;
            }
            st = r;//把最右端点赋值给新的st
            i = j - 1;
        }
        if(!flag) res = -1;
        System.out.print(res);
    }
}

 

2.哈夫曼树

148. 合并果子 - AcWing题库 

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        Queue<Integer> heap = new PriorityQueue<>();//建立一个小根堆
        int n = sc.nextInt();
        while(n -- > 0){
            int x = sc.nextInt();
            heap.add(x);
        }
        int res = 0;
        while(heap.size() > 1){
            int a = heap.peek();//取出两个最小的数
            heap.poll();
            int b = heap.peek();
            heap.poll();
            res += a + b;
            heap.add(a + b);
        }
        System.out.print(res);
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值