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;
}