数据结构与算法 动态规划

动态规划(英语:Dynamic programming,简称DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。

动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。

动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再根据子问题的解以得出原问题的解。

通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。

阅读更多

数据结构与算法 Prim 最小生成树算法

问题分析

在一个有n个节点的无向连通图G = (V, E)中,V表示顶点集,E表示边集。只需n-1条边就可以使这个图连通,n-1条边要想保证图连通,就必须不含回路,所以我们只需要找出n-1条权值最小且无回路的边即可。
图片.png
需要明确几个概念:

  • 生成子图:选中一些边和所有顶点组成的图,称为原图的生成子图。
阅读更多

数据结构与算法 背包算法

背包问题是一种经典的优化问题。有的时候我们需要将有一堆不同重量或者体积的物品放入背包,但是背包容量有限,这时就要寻找一种最优的物品组合,也就是让背包中的物品价值最大化或者重量最小化

背包问题分为0/1背包问题分数背包问题

  • 0/1背包问题是指在背包容量一定的情况下,每个物品只能选择放入背包一次或不放入,要求放入背包中的物品的总价值最大化或者总重量最小化。
  • 分数背包问题是指在背包容量一定的情况下,每个物品可以选择放入部分或全部,要求放入背包中的物品的总价值最大化或者总重量最小化。
阅读更多

数据结构与算法 贪心算法

贪心算法

贪心算法(英语:greedy algorithm),又称贪婪算法,是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法。比如在旅行推销员问题中,如果旅行员每次都选择最近的城市,那这就是一种贪心算法。

贪心算法在有最优子结构的问题中尤为有效。最优子结构的意思是局部最优解能决定全局最优解。简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。

贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。

阅读更多

数据结构与算法 排序算法-基数排序

基数排序

计数排序,它适用于数据量 n 较大但数据范围 m 较小的情况。假设我们需要对 n = 10^6 个学号进行排序,而学号是一个 8 位数字,这意味着数据范围 m = 10^8 非常大,使用计数排序需要分配大量内存空间,而基数排序可以避免这种情况。

「基数排序 Radix Sort」的核心思想与计数排序一致,也通过统计个数来实现排序。在此基础上,基数排序利用数字各位之间的递进关系,依次对每一位进行排序,从而得到最终的排序结果。

算法流程

以学号数据为例,假设数字的最低位是第 1 位,最高位是第 8 位,基数排序的步骤如下:

阅读更多

数据结构与算法 排序算法-桶排序

桶排序

前述的几种排序算法都属于“基于比较的排序算法”,它们通过比较元素间的大小来实现排序。此类排序算法的时间复杂度无法超越 O(n log n) 。接下来,我们将探讨几种“非比较排序算法”,它们的时间复杂度可以达到线性水平。

「桶排序 Bucket Sort」是分治思想的一个典型应用。它通过设置一些具有大小顺序的桶,每个桶对应一个数据范围,将数据平均分配到各个桶中;然后,在每个桶内部分别执行排序;最终按照桶的顺序将所有数据合并。

算法流程

考虑一个长度为 n 的数组,元素是范围 [0, 1) 的浮点数。桶排序的流程如下:

阅读更多

数据结构与算法 排序算法-计数排序

「计数排序 Counting Sort」通过统计元素数量来实现排序,通常应用于整数数组。

简单实现

先来看一个简单的例子。给定一个长度为 n 的数组 nums ,其中的元素都是“非负整数”。计数排序的整体流程如下:

  1. 遍历数组,找出数组中的最大数字,记为 m ,然后创建一个长度为 m + 1 的辅助数组 counter
  2. 借助 counter 统计 nums 中各数字的出现次数,其中 counter[num] 对应数字 num 的出现次数。统计方法很简单,只需遍历 nums(设当前数字为 num),每轮将 counter[num] 增加 1 即可。
阅读更多

数据结构与算法 排序算法-归并排序

「归并排序 Merge Sort」基于分治思想实现排序,包含“划分”和“合并”两个阶段:

  1. 划分阶段:通过递归不断地将数组从中点处分开,将长数组的排序问题转换为短数组的排序问题;
  2. 合并阶段:当子数组长度为 1 时终止划分,开始合并,持续地将左右两个较短的有序数组合并为一个较长的有序数组,直至结束;

归并排序的划分与合并阶段

算法流程

“划分阶段”从顶至底递归地将数组从中点切为两个子数组,直至长度为 1 ;

阅读更多

数据结构与算法 排序算法-堆排序

「堆排序 Heap Sort」是一种基于堆数据结构实现的高效排序算法。我们可以利用已经学过的“建堆操作”和“元素出堆操作”实现堆排序:

  1. 输入数组并建立小顶堆,此时最小元素位于堆顶。
  2. 不断执行出堆操作,依次记录出堆元素,即可得到从小到大排序的序列。

以上方法虽然可行,但需要借助一个额外数组来保存弹出的元素,比较浪费空间。在实际中,我们通常使用一种更加优雅的实现方式。

算法流程

设数组的长度为 n ,堆排序的流程如下:

  1. 输入数组并建立大顶堆。完成后,最大元素位于堆顶。
阅读更多