有序表练习之最大报酬问题

题目描述

有一个Job工作的数据结构,每一种工作有难度和报酬,现在,给你一个int类型的数组,表示各个小伙伴的能力,只有小伙伴的能力大于等于工作难度,才能从事那份工作,现在,请你求出各个小伙伴,在其能力能胜任的工作中,能获取最高报酬的工作?假设每种工作都有无限个岗位。

思路分析

此题,咋一看就像是经典的贪心算法问题,对吧?我的第一反应也是贪心算法,首先,按照工作难度从小到大放入一个小根堆中,然后,把小于当前能力的出堆,再进入一个大根堆中,大根堆根据报酬组织,返回堆顶元素,就是最大报酬的工作。
但是,用上面的贪心解题的话,能解是能解,不过,有一些问题,首先,此题的题意是每种工作有无限个,而堆则是直接弹出了,因此,上述解法更适合于工作数量有限的问题。其次,上述问题给你的是一个能力的数组,最终让你返回的也是一个最大报酬数组,而不是一个人,因此,每一个人都得重新构建堆结构,这复杂度就有点高了,因此,虽然此题很像是用贪心算法解决的题目,实则贪心算法并不合适。
如果贪心算法不合适,那就只能考虑使用其他技巧了,题目给你一个能力的数组,最终返回最高报酬的数组,这不就类似于让你实现一个结构,结构中,先根据难度排序,再根据报酬排序,当你在该结构中找到小于该能力的位置,然后,在左边再找第一个也就是最大的报酬,就是答案。
具体分析题目,首先按照难度排序,在同一个难度时,只有最高报酬的才有效,对吧?因为只会选择最高报酬的,其次,如果难度更高的工作,报酬反而低,那么,这个工作也永远都不会被选择,对吧?因此,可以根据这两点,筛选出剩下的,要求难度依次上升,同时报酬也依次上升,此时,输入一个能力值,小于该能力值的第一份工作,就是答案,因为此结构中,已经把不符合顺序的排除掉了。

代码

数据结构

class Job{
    int hard;
    int money;
    public Job(int hard,int money){
        this.hard=hard;
        this.money=money;
    }
}

class MyComparator implements Comparator<Job>{

    @Override
    public int compare(Job o1, Job o2) {
        //比较器,如果hard相同就比较money,money从大到小
        return o1.hard==o2.hard? o2.money-o1.money: o1.hard-o2.hard;
    }
}

代码

    public static int[] f1(Job[] jobs,int[] abilitys){
        //利用比较器排序,hard从小到大,money从大到小
        Arrays.sort(jobs,new MyComparator());
        //保存结果
        int[] res=new int[abilitys.length];
        //有序表,key是hard,value是money
        TreeMap<Integer,Integer> map=new TreeMap<>();
        //把第一个放进去,key最小value最大的值
        map.put(jobs[0].hard,jobs[0].money);
        Job pre=jobs[0];
        //只保留相同难度的报酬最大值,同时,如果难度增加报酬没增加的直接排除
        for (int i = 1; i < jobs.length; i++) {
            if(jobs[i].hard!=pre.hard&&jobs[i].money>pre.money){
                pre=jobs[i];
                map.put(jobs[i].hard,jobs[i].money);
            }
        }
        //map.floorKey函数返回小于key的第一个数
        for (int i = 0; i < abilitys.length; i++) {
            if(map.floorKey(abilitys[i])!=null){
                res[i]=map.get(map.floorKey(abilitys[i]));
            }else {
                res[i]=0;
            }
        }
        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值