一看就懂的贪心算法

本文主要介绍贪心算法,通过背包问题和商店找零问题举例说明贪心算法是每一阶段做决策都找出当前条件下的最优解。还提到在贪心思想指导下设计的选择排序算法,其排序思想是按阶段将数字从小到大排列,时间复杂度为O(n^2)。

写在前面的话

今天我介绍的主题是贪心算法。这是相对比较容易的一种算法。我这里不给出定义,因为大家可以自行网络搜索。咱们直接看例子。

贪心算法,如果不用手动证明一个问题的数学性质的话,其实是比较简单的。看这样一个例子:假设有一个背包,其最大容量是50KG,现在有各种不同价值的液体,比方说,有水,其价值是10 每千克,共100KG;酒精,其价值是20 每千克,共30KG;有油,价值25每千克,共30KG。问什么样的方案才能使得背包里装的液体的总价值最大?显然,这是一道小学生都会的题目,拣贵的装呗。这谁不会。那就是把30KG油先装了,因为油最贵嘛,剩下20KG的容量装酒精,因为酒精比水贵。

好,那么,这个思维过程就是贪心:每一阶段做决策都找出当前条件下的最优解。当然这个问题,这种解法的正确性显而易见,贪心类的问题最难的地方在于正确性无法证明。这个我们先不管。毕竟我们不是在做算法研究,我们只要能用贪心去解决具体的编程问题就行了。

再看一个简单的例子。

在商店找零,比如说,售货员要找给你37块钱,那什么样的方案才是找钱的张数最少的方案呢?肯定是找回的零钱面值越大,最后的张数越少。所以我们可以使用贪心的方法来解决这个问题。先找一张20的,如果再找一张20的,那就超过37了,这不行,所以就再找一张10块的,然后是5块的和两张一块的。最终的方案就得到了,这也是一次典型的贪心计算方案。

排序

在贪心的思想的指导下,也设计了一种排序算法,这种算法被称为选择排序。排序的思想很简单。既然我的目标是把一堆数字从小到大排,那么我按阶段解决这个问题不就好了么?第一步找到最小的那个数把它放到第一位,第二步在剩下的所有数里再找最小的,把它放到第二位,依次类推。

public class ChooseSort implements  Sorter {
    public void sort(int[] arr) {
        int pivot, pos = -1;

        for (int i = 0; i < arr.length; i++) {
            pivot = Integer.MAX_VALUE;
            for (int j = i; j < arr.length; j++) {
                if (pivot > arr[j]) {
                    pivot = arr[j];
                    pos = j;
                }
            }
            arr[pos] = arr[i];
            arr[i] = pivot;
        }
    }
}

我们从第一趟迭代开始看,这时 i 为0,内部的那个循环,就是从 0 到数组的末尾找到数组中的最小值。然后把这个最小值与第 i 位,这里就是第 0 位,交换。这样,我们就把第一小的数放到数组的第0位了。

第二趟迭代呢,就把从第一位到数组末尾最小的数放到了数组的第1位。

这个过程不断地进行,直到完成 n 趟迭代。明显的,选择排序的时间复杂度是O(n^2)。

看,从算法设计的角度来看排序的问题,是不是感觉排序问题一下子就有章可循了。

<think>好的,用户现在想更好地理解算法。让我先回顾下用户的需求和之前的引用内容。用户之前提供的引用中提到了算法复杂度、算法与数据结构的关系、KNN算法的优点以及SSD算法的细节。用户可能对如何系统地学习和掌握算法有困惑。 首先,我需要确定用户的基础。可能用户是刚开始学习算法,或者有定基础但想深入理解。根据用户的问题,他们可能需要从基础开始,逐步构建知识体系。引用中提到算法是应用程序的核心,所以理解算法的重要性是关键。 接下来,分解问题。用户希望更好地理解算法,这可能包括学习策略、实践方法、理论结合等方面。需要结合引用中的信息,比如引用[2]提到算法和数据结构的关系,所以建议用户同时学习数据结构。引用[1]讨论算法复杂度,因此分析时间复杂度也是重点。 然后,考虑用户可能的痛点。比如,觉得算法抽象难,或者不知道如何应用。需要建议分阶段学习,从简单到复杂,结合实例。例如,引用[3]中的KNN例子,可以推荐通过具体算法来理解通用原理。 还要考虑实践。用户可能需要代码示例和实际项目来加深理解。例如,快速排序的代码示例,以及如何分析其性能(引用[1]中的复杂度比较)。此外,引用[5]中的SSD算法说明,可能用户对应用场景感兴趣,可以建议研究实际案例。 另外,用户可能对数学基础有疑问,比如算法的数学原理。例如,引用[4]中的KNN距离归化涉及数学处理,需要建议补充相关数学知识,如概率、线性代数等。 最后,用户可能需要资源推荐,如经典书籍、在线课程等,以及参与社区讨论。这些都能帮助用户多角度理解算法。 总结回答结构:分步骤的方法,结合理论与实践,强调基础知识和应用,推荐资源,并生成相关问题引导深入思考。</think>要系统性地理解算法,可以按照以下步骤进行: ### 、建立基础知识框架 1. **明确算法定义与目标** - 算法是解决特定问题的明确步骤集合,核心目标包括: $$时间复杂度\ T(n)=O(f(n))$$ $$空间复杂度\ S(n)=O(g(n))$$ 通过渐进符号分析效率[^1] 2. **掌握分类体系** - 按范式分类:分治(如快速排序)、贪心、动态规划、回溯等 - 按领域分类:排序算法$O(n\log n)$、图算法$O(|E|+|V|)$、机器学习算法等[^2] ### 二、采用分层理解方法 1. **第层:流程理解** - 示例:快速排序的分治过程 ```python def partition(arr, low, high): pivot = arr[high] i = low - 1 for j in range(low, high): if arr[j] <= pivot: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i+1], arr[high] = arr[high], arr[i+1] return i+1 ``` 2. **第二层:数学建模** - 推导递归关系式: $$T(n) = 2T(n/2) + O(n)$$ 通过主定理得$T(n)=O(n\log n)$[^1] 3. **第三层:实现优化** - 三数取中法选择基准点 - 尾递归优化减少栈深度 ### 三、实践验证路径 1. **复杂度实验验证** ```python import timeit for n in [100,1000,10000]: t = timeit.timeit(f'sorted([random() for _ in range({
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值