1 我为什么要写这个总结
1.1 字节笔试题
小明在玩一场通关游戏,初始血量为1,关卡有怪兽或者有血包(正数就是血包可回血数,负数说明是怪兽的伤害值),当捡到血包时会加血量,碰到怪兽时会掉血,现在指定初始血量为x,关卡是一个数组,小明必须按照数组的顺序玩游戏,当碰到一个怪兽时,他可以选择将这个怪兽扔到数组末尾,小明可以无限次地将怪兽移到数组末尾,问小明最少移动几次就能存活,如果无论怎么移动都不能存活则返回-1, 假设关卡是这样的[-200,-300,400],则返回-1,假如是这样的[200,100,-250,-60,-70,100],则返回1,只需要把-250挪到尾部,
思路:当发现自己血量不足时,就从当前已经遍历过的所有关卡中,选择耗费血量最多的那个关卡并且放到最后一关,如果即使这样挪开了耗血量最大的一关自身血量还是为负,则直接返回-1,说明无法通关
2 总结
2.1 什么是局部最优?
贪心关注的是局部最优,这里当前最优(指当前遍历的所有元素中的最优解)也是局部最优的一种,而一般的最有解又涉及到数据的最值,而且随着元素的不断向右扩展,可能这个最优值是不断变化的,所以一般可以使用堆来动态维护它的最值。
3 题目
3.1 leetcode1046. 最后一块石头的重量
3.2 leetcode 1642. 可以到达的最远建筑
leetcode 1642. 可以到达的最远建筑
标准答案:
//每次先放梯子,当梯子数量不足时,将当前使用过的梯子中,替代阶梯数最少的梯子找出来用对应砖头替换,替换出来的梯子拿到当前使用public int furthestBuilding(int[] heights, int bricks, int ladders) {int n=heights.length;//int[]:PriorityQueue<Integer>pq=new PriorityQueue<>((o1,o2)->(o1-o2));int i;int sum=0;//表示当前需要的砖块数量for(i=1;i<n;i++){int diff=heights[i]-heights[i-1];if(diff>0){pq.offer(diff);if(pq.size()>ladders){sum+=pq.poll();}if(sum>bricks){return i-1;}}}return n-1;}```我的答案:(有几个特别长的case过不了)```java
public int furthestBuilding2(int[] heights, int bricks, int ladders) {int n=heights.length;PriorityQueue<Integer>pq=new PriorityQueue<>((o1,o2)->(o1-o2));int i;for(i=1;i<n;){int diff=heights[i-1]-heights[i];// System.out.println("i:"+i+",diff:"+diff+",heights[i-1]:"+heights[i-1]+",heights[i]:"+heights[i]);if(diff<0){int diffAbs=-diff;if(ladders>0){ladders--;pq.add(diffAbs);}else if(bricks>=diffAbs){bricks-=diffAbs;}else{int newd=Integer.MAX_VALUE;if(!pq.isEmpty()){newd=pq.peek();}if(bricks>=newd){pq.poll();bricks-=newd;ladders++;i=i-1;}else{break;}}}i++;}return i-1;}
这里还有一个二分查找的方法:
每太整明白: