LC 826. 安排工作以达到最大收益 + LC 904. 水果成篮(滑动窗口)

本文介绍两个算法挑战问题:一是如何通过合理分配不同难度的任务给工人以实现最大收益;二是如何在限定条件下收集尽可能多的水果种类。文章提供了详细的解决方案及代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LC 826. 安排工作以达到最大收益

有一些工作:difficulty[i] 表示第i个工作的难度,profit[i]表示第i个工作的收益。

现在我们有一些工人。worker[i]是第i个工人的能力,即该工人只能完成难度小于等于worker[i]的工作。

每一个工人都最多只能安排一个工作,但是一个工作可以完成多次。

举个例子,如果3个工人都尝试完成一份报酬为1的同样工作,那么总收益为 $3。如果一个工人不能完成任何工作,他的收益为 $0 。

我们能得到的最大收益是多少?

示例:

输入: difficulty = [2,4,6,8,10], profit = [10,20,30,40,50], worker = [4,5,6,7]
输出: 100
解释: 工人被分配的工作难度是 [4,4,6,6] ,分别获得 [20,20,30,30] 的收益。

提示:

  • 1 <= difficulty.length = profit.length <= 10000
  • 1 <= worker.length <= 10000
  • difficulty[i], profit[i], worker[i] 的范围是 [1, 10^5]
// 826. 安排工作以达到最大收益
    /*
    * 思路:
    * 把困难与报酬放在TreeMap中(困难程度一样的工作,报酬存成最大的)
    * 调整:让困难大的,得到的报酬也越大
    * 便利work中的值,找到能取到的最大的报酬
    * */
    public int maxProfitAssignment(int[] difficulty, int[] profit, int[] worker) {
        TreeMap<Integer, Integer> treeMap = new TreeMap<>();

        //困难程度一样的工作,报酬存成最大的
        for (int i = 0; i < difficulty.length; i++) {
            treeMap.put(difficulty[i], Math.max(profit[i], treeMap.getOrDefault(difficulty[i], 0)));
        }

        int max = 0;
        //调整:困难最大的,让报酬也达到最大
        for (int key : treeMap.keySet()) {
            if (treeMap.get(key) < max) {
                treeMap.put(key, max);
            } else {
                max = treeMap.get(key);
            }
        }

        int sum = 0;
        for (int i = 0; i < worker.length; i++) {
            //首先,找到匹配key的entry;
            // 若没有,则找到最小匹配key的值,例如:{1,2,4,6},key=3的话,那么匹配的是key=2的entry
            Map.Entry<Integer,Integer> entry=treeMap.floorEntry(worker[i]);
            if ( entry!= null) {
                sum += entry.getValue();
            }
        }
        return sum;
    }

LC 904. 水果成篮

在一排树中,第 i 棵树产生 tree[i] 型的水果。
你可以从你选择的任何树开始,然后重复执行以下步骤:

  • 把这棵树上的水果放进你的篮子里。如果你做不到,就停下来。
  • 移动到当前树右侧的下一棵树。如果右边没有树,就停下来。

请注意,在选择一颗树后,你没有任何选择:你必须执行步骤 1,然后执行步骤 2,然后返回步骤 1,然后执行步骤 2,依此类推,直至停止。

你有两个篮子,每个篮子可以携带任何数量的水果,但你希望每个篮子只携带一种类型的水果。
用这个程序你能收集的水果总量是多少?

示例 1:

输入:[1,2,1]
输出:3
解释:我们可以收集 [1,2,1]。

示例 2:

输入:[0,1,2,2]
输出:3
解释:我们可以收集 [1,2,2].
如果我们从第一棵树开始,我们将只能收集到 [0, 1]。

示例 3:

输入:[1,2,3,2,2]
输出:4
解释:我们可以收集 [2,3,2,2].
如果我们从第一棵树开始,我们将只能收集到 [1, 2]。

示例 4:

输入:[3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:我们可以收集 [1,2,1,1,2].
如果我们从第一棵树或第八棵树开始,我们将只能收集到 4 个水果。

方法1:

   //904. 水果成篮
    /*
    * 滑动窗口的思想:
    * i,j均指向左端
    * i固定,j向右遍历,一次找到当前的max值
    * */
    public int totalFruit(int[] tree) {
        HashMap<Integer, Integer> count = new HashMap<>();
        int res = 0;
        int i = 0;
        for (int j = 0; j < tree.length; j++) {
            count.put(tree[j], count.getOrDefault(tree[j], 0) + 1);
            while (count.size() > 2) {
                count.put(tree[i], count.get(tree[i]) - 1);
                if (count.get(tree[i]) == 0)
                    count.remove(tree[i]);
                i++;//向右滑动,关键的地方
            }
            res = Math.max(res, j - i + 1);//满足条件,当前的最大值
        }
        return res;
    }

方法2:

    //滑动窗口:这个方法好棒哦
    public int totalFruit2(int[] tree) {
        //用于存储每类水果的个数
        int[] map=new int[40001];
        int i=0;
        int res=0;
        //用于存储目前有几类水果
        int count=0;
        for(int j=0;j<tree.length;j++){
            if(map[tree[j]]==0){
                count++;
            }
            map[tree[j]]++;
            while (count>2){
                map[tree[i]]--;
                if(map[tree[i]]==0){
                    count--;
                }
                i++;
            }
            res=Math.max(res,j-i+1);
        }
        return res;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值