K 次取反后最大化的数组和
这道题也是贪心算法,很简单,维护一个最小堆,每次取反最小值就可以了
class Solution {
public int largestSumAfterKNegations(int[] nums, int k) {
int res = 0;
PriorityQueue<Integer> que = new PriorityQueue<>();
for(int i = 0;i < nums.length;i ++){
que.add(nums[i]);
}
for(int j = 0;j < k;j ++){
int out = que.poll();
que.add(-out);
}
while(!que.isEmpty()){
res += que.poll();
}
return res;
}
}
加油站
这道题得从两个角度去判断,首先判断gas的总和是否能包括cost,如果不能包括直接返回-1,然后在推导局部最优——当gas - cost能覆盖的时候直接更新start为第一次覆盖的下标,一旦不能覆盖,则从下一个下标重新开始
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
// 首先从全局来看,如果cost总和大于gas,那么一定不能够支持跑一圈,所以首先计算出总cost和总gas进行比较,成功进行下一步
// 然后按照贪心的思想,只要gas可以覆盖当前cost,就可以进行选择,如果不能的话,从i + 1开始
//当前收获和前往下一个节点的差距
int cur = 0;
// 判断总和是否大于0
int sum = 0;
// 开始的位置
int start = 0;
for(int i = start;i < cost.length;i ++){
sum += gas[i] - cost[i];
cur += gas[i] - cost[i];
// 当获得的gas小于下一站的花费,直接从下一站重新开始计算
if(cur < 0){
start = i + 1;
cur = 0;
}
}
// 总和小于0直接返回
if(sum < 0){
return -1;
}
return start;
}
}
分发糖果
分发糖果需要考虑元素的左右元素的大小,所以需要两次遍历,一次统一右侧元素,一次统一左侧元素
在统一右侧元素时,唯一遵守的就是:只要当前的分比上一个高,就在上一个的基础上加一
在统一左侧元素的时候,与统一右侧元素不同的是,我们要在满足右侧元素的基础上维护左侧元素,所以就取两次结果的最大值
注意事项:注意循环的范围限制和数组的值是前一个还是后一个
class Solution {
public int candy(int[] ratings) {
int len = ratings.length;
// 糖果数量对比
int[] candyVec = new int[len];
candyVec[0] = 1;
// 糖果数组和
int sum = 0;
// 循环对比
for(int i = 1;i < len;i ++){
candyVec[i] = (ratings[i] > ratings[i - 1]) ? candyVec[i - 1] + 1 : 1;
}
// 从后向前
for(int i = len - 2;i >= 0;i --){
if(ratings[i] > ratings[i + 1]){
candyVec[i] = Math.max(candyVec[i],candyVec[i + 1] + 1);
}
}
for(int i : candyVec){
sum += i;
}
return sum;
}
}
柠檬水找零
我们要先做一次数组第一个元素的判断,如果元素大于5,那么就要拜拜了,使用哈希存储目前手里有的钱,其实就是读到数字,然后add,同时找零的那个钱remove掉
class Solution {
public boolean lemonadeChange(int[] bills) {
// 如果第一个元素大于5直接寄
if(bills[0] > 5){
return false;
}
int len = bills.length;
Map<Integer,Integer> cash = new HashMap<>();
cash.put(5,0);
cash.put(10,0);
for(int i = 0;i < len;i ++){
cash.put(bills[i],cash.getOrDefault(bills[i],0) + 1);
int change = bills[i] - 5;
if(change == 5){
if (cash.get(5) > 0) {
cash.put(5, cash.get(5) - 1);
} else {
return false;
}
}else if(change == 15){
if(cash.get(10) > 0 && cash.get(5) > 0){
cash.put(10, cash.get(10) - 1);
cash.put(5, cash.get(5) - 1);
}else if(cash.get(5) >= 3){
cash.put(5, cash.get(5) - 3);
}else{
return false;
}
}
}
return true;
}
}
找出缺失和重复的数字
这是每日一题
一开始思路跑偏了,想着用HashMap解决,后来一想,HashMap是无序的,只能算出那个元素重复了,没办法判断少了哪个元素,所以用了暴力的解决方法,直接把grid拉长有序化,新建一个对比数组count,如果元素存在,则在该下标出+1表示元素出现了一次,当元素是4的时候,就会在count[4]处填写1,出现第二次则再次自增填写2,然后遍历count就可以了,时间复杂度是On2
class Solution {
public int[] findMissingAndRepeatedValues(int[][] grid) {
int n = grid.length;
int[] res = new int[2];
int[] count = new int[n * n + 1];
for(int[] row : grid){
for(int i : row){
count[i] ++;
}
}
for(int i = 0;i < count.length;i ++){
if(count[i] == 2){
res[0] = i;
}
if(count[i] == 0){
res[1] = i;
}
}
return res;
}
}
emmm,力扣上耗时有点大,可以考虑一下优化