简单学习一下贪心算法

128 阅读2分钟

前言

晚上的毛概课上闲的无聊看了点贪心算法的文章,浅浅学习了一下,下面主要通过两道题目浅显讲解一下,算是对自己学习的一种记录吧,有问题欢迎指出!

贪心算法(Greedy Algorithm)

贪心算法,又称贪婪算法,是一种寻找最优解问题的常用方法。这种方法模式一般将求解过程分成若干个步骤,但每个步骤都应用贪心原则,选取当前状态下最好或最优的选择(局部最有利的选择),并以此希望最后堆叠出的结果也是最好或最优的解

从我个人理解上讲就是,它只关心局部最优解,而不关心是否全局最优解。就像一个贪心的人,只在乎短期内能获得的最大利益,而不会去关心长期范围内的最大利益

一、剪绳子

小明有一根n米长的绳子,要你剪成m段(n,m都是整数,并且n>1,m>1),并且小明要你帮他求出m段绳子长度的最大乘积。

例如:

输入:n = 12
输出:81
过程:3 + 3 + 3 + 3 = 12   3 × 3 × 3 × 3 = 81

解题思路

将每段绳子尽可能的剪成3米长,最后剩下的长度不足三米则与上一段绳子组合。证明过程如下:

条件:n,m都为整数,并且 n>1, m>1
设 绳子剪成两段,分别为 `x``x-n`,列计算公式: x(n-x)-n
`x``1`时,x(n-x)-n = 1(n-1)-n = n<1,即剪开后的乘积一定最小,因此不能出现长度为1的绳子
`x``2`时,x(n-x)-n = 2(n-2)-n = n>=4 因此在 n>=4 时剪开后得到的乘积会比不剪的更大
`x``3`时,x(n-x)-n = 3(n-3)-n = 2n-9 ≈ n>=5 因此在 n>=5是效果最好
`x``4`时,因为4 = 2 × 2,因此效果跟为2时一样
`x``5`时,因为5 = 3 + 2,又因为5 < 3 × 2,因此不能出现为5的绳子,而是剪成32,乘积会更大
`x``6`时,因为6 = 3 + 3,又因为6 < 3 × 3,又可剪成6 = 2 + 2 + 2,但是3(n-3)-2n(n-2) = n>=5,而在n>=5下,将绳子剪成3的效果比剪成2的好
...以此类推发现为3的结果是最好的

代码实现

function cutRope(n) {
    if (n < 2) return 0
    if (n === 2) return 1
    if (n === 3) return 2
    let surplus = 0
    surplus = n % 3
    return Math.pow(3, ((n - surplus) / 3) - 1) * (3 + surplus)
}

console.log(cutRope(12)); // 81

复杂度分析

时间复杂度 O(1): 仅有求整、求余、次方运算。

空间复杂度 O(1): 变量n、surplus 使用常数大小额外空间。

二、找零钱

小王是一家超市的收银员,这天有顾客来店里购买了商品,需要你找零n元,现在有面值100、50、20、10、5、1的纸币,请你以最少张纸币给顾客找零

例如:

输入:n = 146
输出:[1,0,2,0,1,1]

解题思路

题目要求用最少的张数给顾客找零,那么我们就需要先从最大面值找,比如146,先给100面值的纸币剩下46元,再给2张20面值的纸币剩下6元,再给1张5面值的纸币剩下1,再给1张1面值的纸币便找零完成

代码实现

function giveChange(n) {
    const allMoney = [100, 50, 20, 10, 5, 1]
    const result = []
    for (let i = 0; i < allMoney.length; i++) {
        const money = allMoney[i]
        if (n >= money) {
            const surplus = n % money
            result.push((n - surplus) / money)
            n = surplus
        }
        else{
            result.push(0)
        }
    }
    return result
}

console.log(giveChange(146)); // [ 1, 0, 2, 0, 1, 1 ]

复杂度分析

时间复杂度 O(1): 循环次数固定是allMoney数组的长度

空间复杂度 O(1): 常量allMoney、result的长度都是固定的

总结

从上面两道题目我们不难看出,贪心算法就是只关心局部最优解而不关心是否全局最优解,无论是剪绳子还是找零钱,都是只关注局部最优解