贪心算法part3
贪心算法part3
134. 加油站 - 力扣(LeetCode)
总体思路:
- 如果gas[i]总和 > cost[i]总和, 不可能跑完, 直接返回-1
- 贪心: 新增一个rest数组, 计算当前的gas[i] - cost[i]总和, 如果总和小于0, 那么更新答案下标为i + 1
- 局部最优: 当前累加rest[i]的和curSum一旦小于0,起始位置至少要是i+1,因为从i之前开始一定不行。
- 全局最优:找到可以跑一圈的起始位置。
代码:
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int[] rest = new int[gas.length];
int curSum = 0;
int res = 0;
for(int i = 0; i < rest.length; i++){
curSum += gas[i];
curSum -= cost[i];
}
if(curSum < 0){
return -1;
}
curSum = 0;
for(int i = 0; i < rest.length; i++){
rest[i] = gas[i] - cost[i];
curSum += rest[i];
if(curSum < 0){
res = i + 1;
curSum = 0;
}
}
return res;
}
}
135. 分发糖果 - 力扣(LeetCode)
难度为困难
这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼。
贪心策略:
- 一次是从左到右遍历,只比较右边孩子评分比左边大的情况
- 一次是从右到左遍历,只比较左边孩子评分比右边大的情况
代码如下:
class Solution {
public int candy(int[] ratings) {
int[] candies = new int[ratings.length];
Arrays.fill(candies, 1);
for(int i = 1; i < ratings.length; i++){
if(ratings[i] > ratings[i - 1]){
candies[i] = candies[i - 1] + 1;
}
}
for(int i = ratings.length - 1; i > 0; i--){
if(ratings[i - 1] > ratings[i]){
candies[i - 1] = candies[i - 1] > candies[i] + 1 ? candies[i - 1] : candies[i] + 1; //这里是特殊情况,局部贪心,如果当前节点是山峰,要确保当前节点改动之后还是山峰
}
}
int res = 0;
for(int i = 0; i < candies.length; i++){
res += candies[i];
}
return res;
}
}
tips:
数组填充函数:
Arrays.fill(array[], int)
860. 柠檬水找零 - 力扣(LeetCode)
唯一贪心的体现:收取20时,优先用10支付,没啥意思这题
class Solution {
public boolean lemonadeChange(int[] bills) {
HashMap<Integer, Integer> record = new HashMap<>();
record.put(5, 0);
record.put(10, 0);
for(int i = 0; i < bills.length; i++){
if(bills[i] == 5){
record.put(5, record.get(5) + 1);
}else if(bills[i] == 10){
int num = record.get(5);
if(num < 1){
return false;
}
record.put(5, num - 1);
record.put(10, record.get(10) + 1);
}else{
int num5 = record.get(5);
int num10 = record.get(10);
if(num5 < 1){
return false;
}else if(num5 <= 2 && num10 < 1){
return false;
}else if(num10 > 0){
record.put(10, num10 - 1);
record.put(5, num5 - 1);
}else {
record.put(5, num5 - 3);
}
}
}
return true;
}
}
406. 根据身高重建队列 - 力扣(LeetCode)
本题要从两个维度考虑排序,一个是身高维度,另一个是根据身高排序
为什么要先从身高考虑,进行第一次排序?
- 因为先将身高从大到小排序之后,再根据身高进行排序,那么小身高无论放在大身高的前还是后,都不会对大身高造成影响,最后得到的队列一定没问题
此题思路很好理解,但是Java的语法不太好写,需要排序器学的很好
class Solution {
public int[][] reconstructQueue(int[][] people) {
Arrays.sort( people, (a, b) -> {
if(a[0] == b[0]){
return a[1] - b[1]; //同身高情况下,升序
}
return b[0] - a[0]; //身高按降序排列
});
LinkedList<int[]> res = new LinkedList<>(); //使用linkedList进行结果的构建,队列
for(int[] arr : people){
res.add(arr[1], arr); // arr[1]是插入的位置, arr是要插入的数组
}
return res.toArray(new int[people.length][]);
}
}
浙公网安备 33010602011771号