数据结构与算法系列 --- 贪心算法

1、钱币找零问题

题目:问题描述:分别有1,5,10,50,100元, 分别有5,2,2,3,5张纸币。问若要支付k元,则最少需要多少张纸币?

解题思路:每次选择支付的纸币时,尽量选择面额最大的,这样每次获得的都是局部最优的选择,直到满足 k 元为止

 

Java代码如下:

public class GreedyTest1 {
    /**
     * 题目:问题描述:分别有1,5,10,50,100元,
     * 分别有5,2,2,3,5张纸币。问若要支付k元,则需要多少张纸币?
     */
    @Test
    public void test1(){
        int[]  money = {1,5,10,50,100};
        int[]  moneyNum = {5,2,2,3,5};

        int k = 316;   //待支付的钱数
        int count = 0;  //需要付款的纸币数目
        for(int i=money.length-1;i>=0;i--){  //从最大面额的纸币开始选择,假设面额大小已经按照升序排列
            while (k>=money[i] && moneyNum[i]>0){  
                k -= money[i];    //总额减去当前最大的纸币额度值
                moneyNum[i] -= 1;  
                count += 1;
            }
        }

        System.out.println("最少需要的纸币数量:"+count);

    }
}

输出结果:

    最少需要的纸币数量:6

 

2、区间调度问题

题目:假设我们有 n 个区间,区间的起始端点和结束端点分别是[l1, r1],[l2, r2],[l3, r3],……,[ln, rn]。 我们从这 n 个区间中选出一部分区间,这部分区间满足两两不相交(端点相交的情况不算相交),最多能选出多少个区间呢? 

比如例子:{6,8},{2,4},{3,5},{1,5},{5,9},{8,10}

思路:每次在选择区间时,要满足当前区间的左端点的数值小于上一个区间的右端点,且当前区间的右端点在剩下的区间中最小

Java代码如下:

public class GreedyTest1 {

    /**
     * 区间调度问题
     * 2、题目:假设我们有 n 个区间,区间的起始端点和结束端点分别是[l1, r1],[l2, r2],[l3, r3],……,[ln, rn]。
     * 我们从这 n 个区间中选出一部分区间,这部分区间满足两两不相交(端点相交的情况不算相交),最多能选出多少个区间呢?
     *  例子:{6,8},{2,4},{3,5},{1,5},{5,9},{8,10}
     *  结果:
     *      {2,4}
     *      {6,8}
     *      {8,10}
     */

      @Test
    public void test3(){
        int[][]  data = {{6,8},{2,4},{3,5},{1,5},{5,9},{8,10}};
        //先将原始数据 data 按照右端点的数值大小升序排列
        boolean flag = true;
        for(int i=0;i<data.length-1;i++){
            flag = true;
            for(int j=i+1;j<data.length;j++){
                if(data[j][1]<data[i][1]){
                    int[] tmp = data[j];
                    data[j]   = data[i];
                    data[i]   = tmp;
                    flag = false;
                }
            }
            if(flag){
                break;
            }
        }
        System.out.println("将原始数据 data 按照右端点的数值大小升序排列: ");
        for(int[] d:data){
            System.out.print("{"+d[0]+","+d[1]+"}\t");
        }

        List<int[]>  result = new LinkedList<>();
        int lr = Integer.MIN_VALUE;

        for(int[] d:data){   //每次从data中取出的区间,均为剩下区间中右端点最小的区间
            if(d[0]>=lr){   //当前区间若满足左端点小于上一个区间的右端点,则将当前区间加入结果 result 中
                result.add(d);
                lr = d[1];
            }
        }
        System.out.println("最多能选出的区间数目:"+result.size());
        System.out.println("满足最多能选出的区间如下:");

        for(int[] d:result){
            System.out.print("{"+d[0]+","+d[1]+"}\t");
        }
    }

}

输出结果:

将原始数据 data 按照右端点的数值大小升序排列: 
{2,4}	{3,5}	{1,5}	{6,8}	{5,9}	{8,10}	最多能选出的区间数目:3
满足最多能选出的区间如下:
{2,4}	{6,8}	{8,10}	

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值