贪心力扣,poj相关算法题

13 篇文章 0 订阅

贪心: 遵循某种规律,不断贪心的选取当前最优策略的算法设计方法。

一、预备知识:贪心算法找钱

1,510,20,100,200元的钞票无穷多张,现使用这些钞票支付x元,最少需要多少张?

思路:都是倍数关系,尽可能多的使用面值最大的钞票。

//贪心算法找钱
var findMoney = function(x){
	let moneyArr = [200,100,20,10,5,1];
	let count = 0;
	for(let i = 0;i<moneyArr.length;i++){
		count += Math.floor(x/moneyArr[i]);
		x = x%moneyArr[i]
	}
	return count
}
console.log(findMoney(200))

二、分糖果455

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

 
示例 1:

输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1

思路: 让更多孩子满足。某个孩子可以用多个糖果满足,用更小的满足他。某个糖果可以满足多个孩子,把糖果分给需求更多的孩子。排序后,某个糖果如果不能满足某个孩子的需求,则该糖果也不能满足需求更大的孩子。

var findContentChildren = function(g, s) {
    let child = 0;
    let cookie = 0;
    g.sort((a,b)=>a-b)
    s.sort((a,b)=>a-b)
    while(cookie < s.length){
        if(g[child] <= s[cookie]){
            child++;
            cookie++;
        }else{
            cookie++;
        }
    }
    return child
};

三、摇摆序列376

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

相反,[1, 4, 7, 2, 5][1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

示例 1:

输入:nums = [1,7,4,9,2,5]
输出:6
解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3)

思路:(贪心算法,自己写出来之后发现是贪心)
用count计数,用op代表nums[i+1]-nums[i]的结果为正数或者负数,如果结果为负数,op=0;如果结果为正数,op=1;遍历nums,如果后-前>0&&op=0,count就++,把op设为1;如果后-前<0&&op=1,count就++,把op设置为0。注意给op赋初始值!!!遍历Nums,碰到第一组后-前>0的,把op设为0;出现第一组后-前<0的,把op设为1.(这样防止碰到[3,3,3,5,4]这种类型的数据)

var wiggleMaxLength = function(nums) {
    let count = 1;
    let op = 0;//1代表结果为正数,0代表结果为负数
    for(let i = 0;i<nums.length - 1;i++){
        if(nums[i+1]!==nums[i]){
            if(nums[i+1]-nums[i]>0){op = 0;break;};
            if(nums[i+1]-nums[i]<0){op = 1;break;};
        }
    }
    for(let i = 0;i<nums.length - 1;i++){
        if(nums.length < 2){
            return nums.length;
        }else if(nums[i+1] - nums[i] > 0&&op===0){
            count++;
            op = 1;
        }else if(nums[i+1] - nums[i] < 0&&op===1){
            count++;
            op = 0;
        }
    }
    return count;
};

四、移除k个数字402

给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。
 
示例 1 :

输入:num = "1432219", k = 3
输出:"1219"
解释:移除掉三个数字 4, 3,2 形成一个新的最小的数字 1219

思路: 从高位到低位遍历,结合栈。如果栈顶大于下一位数字,就弹出。注意要处理掉数字的前导0.

var removeKdigits = function(num, k) {
    let stack = [];//定义一个栈
    let number = '';
    if(num.length<=k){
        return '0'
    }
    for(let i = 0;i<num.length;i++){
        while(stack.length!==0&&stack[stack.length-1]>num[i]&&k>0){
            stack.pop();
            k--;
        }
        if(num[i]!==0||stack.length!==0){
            stack.push(num[i])
        }
    }
    while(stack.length!==0&&k>0){
        stack.pop();
        k--;
    }
    for(let i = 0;i<stack.length;i++){
        number += stack[i]
    }
    number = number.replace(/\b(0+)/gi,"")
    if(number===''){
        return '0'
    }
    return number
};

五、跳跃游戏55

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。

示例 1:
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 13 步到达最后一个下标。

思路: 从第i个位置,最远可以跳到nums[i],在这个范围内,贪心选择跳到步数更大的那一个。用jump代表当前所处位置,max_index代表最大的。直到Jump到达index数组尾部或者max_index<nums.length&&jump>=max_index时,返回false.扫描过程中要更新max_index.

var canJump = function(nums) {
    let jump = 0;
    let max_index = 0;
    let index = [];
    for(let i = 0;i < nums.length;i++){
        index[i] = i + nums[i];
        jump = i;
        if(index[i] > max_index){
            max_index = index[i];
        }
        if(jump >= max_index&&max_index<nums.length-1){
            return false;
        }
    }
    return true;
};

六、跳跃游戏2

七、射击气球452

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。
一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足  xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。
给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 。
示例 1:
输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:气球可以用2支箭来爆破:
-在x = 6处射出箭,击破气球[2,8][1,6]-在x = 11处发射箭,击破气球[10,16][7,12]

思路: 先按左节点排序,维持一个可以射击到最多气球的射击区间,左节点比较该节点和射击区间的左节点谁大,并且不能大过射击区间的右节点;右节点比较该节点和射击区间的右节点谁小。如果该节点的左节点大于射击节点的右节点,更新射击区间,并且让shoot_num++.

var findMinArrowShots = function(points) {
    let shoot_num = 1;//弓箭次数
    points.sort((a,b)=>{
        return a[0] - b[0]
    })
    let range = points[0]
    for(let i = 1;i<points.length;i++){
        if(points[i][0]>range[0]&&points[i][0]<range[1]){
            range[0] = points[i][0]
        }
        if(points[i][1] < range[1]){
            range[1] = points[i][1]
        }
        if(points[i][0] > range[1]){
            shoot_num++;
            range = points[i]
        }
    }
    return shoot_num
};

八、最优加油方法

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值