刷题时间:2021.7.24-2021.7.25
贪心法:遵循某种规律,不断贪心的选取当前最优策略的算法设计方法。
当前最优解即为全局最优解,贪心成立。
1、LeetCode455分发饼干
思路:1.对需求因子数组g与饼干大小数组s进行从小到大的排序。
2.按照从小到大的顺序使用各饼干尝试是否可满足某个孩子,每个饼干只尝试1次;若尝试成功,则换下一个孩子尝试;直到发现没更多的孩子或者没更多的饼干,循环结束。
class Solution {
public int findContentChildren(int[] g, int[] s) {
int child = 0;
int cookie = 0;
Arrays.sort(g);
Arrays.sort(s);
while (child < g.length && cookie < s.length ){ //当孩子或饼干同时均未尝试完时
if (g[child] <= s[cookie]){ //当孩子的满足因子小于或等于饼干大小时
child++;//该饼干满足了孩子,孩子向后移动
}
cookie++; // 无论成功或失败,每个饼干只尝试一次,饼干向后移动
}
return child;
}
}
2、LeetCode376摆动序列
思路:当序列有一段连续的递增(或递减)时,为形成摇摆子序列,我们只需要保留这段连续的递增(或递减)的首尾元素,这样更可能使得尾部的后一个元素成为摇摆子序列的下一个元素。
class Solution {
public int wiggleMaxLength(int[] nums) {
int n = nums.length;
if (n < 2) {//序列个数小于2时直接为摆动序列
return n;
}
int begin = 0;//扫描序列时的三种状态
int up = 1;
int down = 2;
int state = begin;
int maxn = 1;//摆动序列最大长度至少为1
for (int i = 1; i < n; i++) {//从第二个元素开始扫描
if (state == begin) {
if (nums[i] > nums[i - 1]){
state = up;
maxn++;
}else if(nums[i] < nums[i - 1]){
state = down;
maxn++;
}
}
else if (state == up) {
if(nums[i] < nums[i - 1]){
state = down;
maxn++;
}
}else if(state == down){
if (nums[i] > nums[i - 1]){
state = up;
maxn++;
}
}
}
return maxn;
}
}
LeetCode评论代码
class Solution {
public int wiggleMaxLength(int[] nums) {
int n = nums.length;
if (n < 2) {
return n;
}
int up = 1;
int down = 1;
for (int i = 1; i < n; i++) {
if (nums[i] > nums[i - 1]) {
up = down + 1;
}
if (nums[i] < nums[i - 1]) {
down = up + 1;
}
}
return Math.max(up, down);
}
}
3、LeetCode402移掉K位数字
思路:从高位向低位遍历,如果对应的数字大于下一位数字,则把该位数字去掉,得到的数字最小!
使用栈存储最终结果或删除工作,从高位向低位遍历num,如果遍历的数字大于栈顶元素, 则将该数字push入栈,如果小于栈顶元素则进行pop弹栈,直到栈为空或不能再删除数字(k==0)或栈顶小于当前元素为止。
class Solution {
public String removeKdigits(String num, int k) {
Stack<Integer>stack=new Stack<>();
for(int i=0;i<num.length();i++){//从最高位循环扫描数字num
int number = num.charAt(i)-'0';
//可能好几个值都比当前值大,那么我们就在k允许的情况下,去去除它。
while(!stack.isEmpty() && k>0 && number<stack.peek()){
stack.pop();
k--;
}
if(number!=0||!stack.isEmpty()){
stack.push(number);
}
}
//56789这种情况,前面一直比后面小,那就去除栈顶,谁让栈顶最大
while(k>0 && !stack.isEmpty()){
stack.pop();
k--;
}
//10,1(当number=0时,满足条件,去掉1,但now为0,且为空。)
if(stack.isEmpty())
return "0";
StringBuilder sb=new StringBuilder();
while(!stack.isEmpty())
sb.append(stack.pop());
//从后往前添加所以我们要逆序
return sb.reverse().toString();
}
}
4、LeetCode55跳跃游戏
public class Solution {
public boolean canJump(int[] nums) {
int n = nums.length;
int[] index = new int[n];//最远可跳至位置
for (int i = 0; i < n; i++) {
index[i] = i + nums[i];//计算index数组
}
int jump = 0,max_index = index[0];
while(jump<n && jump<=max_index){//直到jump跳至数组尾部或jump超越了当前可以跳的最远位置
if(max_index<index[jump]){
max_index = index[jump];//如果当前可以跳的更远,则更新max_index
}
jump++;//扫描jump
}
if(jump == n){
return true;
}
return false;
}
}
LeetCode题解
在遍历的过程中,如果最远可以到达的位置大于等于数组中的最后一个位置,那就说明最后一个位置可达,我们就可以直接返回 True 作为答案。反之,如果在遍历结束后,最后一个位置仍然不可达,我们就返回 False 作为答案。
public class Solution {
public boolean canJump(int[] nums) {
int n = nums.length;
int rightmost = 0;
for (int i = 0; i < n; ++i) {
if (i <= rightmost) {
rightmost = Math.max(rightmost, i + nums[i]);
if (rightmost >= n - 1) {
return true;
}
}
}
return false;
}
}
5、LeetCode45跳跃游戏 II
class Solution {
public int jump(int[] nums) {
int n = nums.length;
if(n < 2) return 0;
int current_max_index = nums[0];//当前可达到的最远位置
int pre_max_index = nums[0];//遍历各个位置中,可达到的最远位置
int jump_min = 1;
for (int i = 1; i < n; i++) {
if (i > current_max_index) {//若无法再向前移动了,才进行跳跃
jump_min++;
current_max_index = pre_max_index;//即更新当前可达到的最远位置
}
if(pre_max_index < nums[i]+i){
pre_max_index = nums[i]+i;
}
}
return jump_min;
}
}
LeetCode题解
「贪心」地进行正向查找,每次找到可到达的最远位置,就可以在线性时间内得到最少的跳跃次数。
class Solution {
public int jump(int[] nums) {
int length = nums.length;
int end = 0;
int maxPosition = 0;
int steps = 0;
for (int i = 0; i < length - 1; i++) {
maxPosition = Math.max(maxPosition, i + nums[i]);
if (i == end) {
end = maxPosition;
steps++;
}
}
return steps;
}
}
6、LeetCode452用最少数量的箭引爆气球
思路:1.对各个气球进行排序,按照气球的左端点从小到大排序。
2.遍历气球数组,同时维护一个射击区间,在满足可以将当前气球射穿的情况下,尽可能击穿更多的气球,每击穿一个新的气球,更新一次射击区间(保证射击区间可以将新气球也击穿)。
3.如果新的气球没办法被击穿了,则需要增加一名弓箭手,即维护一个新的射击区间(将该气球击穿),随后继续遍历气球数组。
class Solution {
public int findMinArrowShots(int[][] points) {
if (points.length == 0) {
return 0;
}
//java.lang包的Integer类的compare()方法比较作为参数给出的两个整数值(x,y),如果(x == y)则返回零,如果(x <y)则返回小于零,如果(x> y),则返回大于零的值。
Arrays.sort(points,(a,b)->Integer.compare(a[1],b[1]));
// Arrays.sort(points, new Comparator<int[]>() {
// public int compare(int[] point1, int[] point2) {
// if (point1[1] > point2[1]) {
// return 1;
// } else if (point1[1] < point2[1]) {
// return -1;
// } else {
// return 0;
// }
// }
// });
//对气球按左端点从小到大排序
int shoot_num = 1;//初始化弓箭手数量为1
int shoot_begin = points[0][0];//初始化射击区间,即为第一个气球的两端点
int shoot_end = points[0][1];
for (int i = 1; i < points.length; i++) {
if (points[i][0]<=shoot_end) {
shoot_begin = points[i][0];
if(shoot_end>points[i][1]){
shoot_end = points[i][1];
}
}else{
shoot_num++;//在保证当前气球被射穿的条件下,射击区间不能再更新了,需要增加一个新的射击区间了
shoot_begin = points[i][0];
shoot_end = points[i][1];
}
}
return shoot_num;
}
}
LeetCode评论代码
class Solution {
public int findMinArrowShots(int[][] points) {
if (points.length == 0) return 0;
Arrays.sort(points, (o1, o2) -> Integer.compare(o1[0], o2[0]));
int count = 1;
for (int i = 1; i < points.length; i++) {
if (points[i][0] > points[i - 1][1]) {// 气球i和气球i-1不挨着,注意这里不是>=
count++;// 需要一支箭
} else {// 气球i和气球i-1挨着
points[i][1] = Math.min(points[i][1],points[i - 1][1]);// 更新重叠气球最小右边界
}
}
return count;
}
}
7、LeetCode871最低加油次数
(这个代码没写出来)
思路:1.设置一个最大堆,用来存储经过的加油站的汽油量。
2.按照从起点至终点的方向,遍历各个加油站之间与加油站到终点距离。
3.每次需要走两个加油站之间的距离d,如果发现汽油不够走距离d时,从最大堆中取出一个油量添加,直到可以足够走距离d。
4.如果把最大堆的汽油都添加仍然不够行进距离d,则无法达到终点。
5.当前油量p减少d。
6.将当前加油站油量添加至最大堆。
LeetCode题解
dp[i] 为加 i 次油能走的最远距离,需要满足 dp[i] >= target 的最小 i。
class Solution {
public int minRefuelStops(int target, int startFuel, int[][] stations) {
int N = stations.length;
long[] dp = new long[N + 1];
dp[0] = startFuel;
for (int i = 0; i < N; ++i){
for (int t = i; t >= 0; --t){
if (dp[t] >= stations[i][0]){
dp[t+1] = Math.max(dp[t+1], dp[t] + (long) stations[i][1]);//每多一个加油站 station[i] = (location, capacity),如果之前可以通过加 t 次油到达这个加油站,现在就可以加 t+1 次油得到 capcity 的油量。
}
}
}
for (int i = 0; i <= N; ++i){
if (dp[i] >= target) return i;
}
return -1;
}
}