文章目录
- 前言
- 题型
- 排序问题
- 动态规划
前言
本文把刷题过程中的总结记下来,方便未来回顾的时候继续拓展。
题型
排序问题
排序问题的解决方法有很多。对于简单算法来说,最重要的是记住思路;对于高级算法来说,最重要的是记住细节。
简单的算法比如选择、冒泡、插入排序,他们的时间复杂度都是 O ( n 2 ) O(n^2) O(n2),所以就算是后面高级的排序算法需要用子排序算法时,我们也不会使用这种高时间复杂度的排序算法。对于这种算法最重要的是记住思路,因为编程难度不会很大。
选择排序也就是冒泡排序,他的思路是从第一个元素开始,跟他的后一个元素比较,如果比他小,他们就交换。如果比他大,就不用交换。然后选择数组中的第二个元素,同样的与后一个进行比较,然后以此类推,这样子当我们进行一轮一后,最后一个元素是所有元素中最大的,当我们进行n-1轮以后,数组就排好了。这就是选择排序,也叫冒泡排序。实现起来难度不大,两层循环就够了。
插入排序就是将无序数组中的元素逐个插入到有序数组中。首先选择无序数组中的第一个元素,然后在有序数组中从第一个位置开始找,如果比他大(假设顺序是从小到大的),那么这个有序数组中的索引位置就是这个元素的插入位置。然后再选择无序数组中第二个元素,以此类推。由于他每次插入一个元素,所以叫插入排序。
由于高级算法大多是将一个数组分为两个进行处理的,然后再将两个分数组合并,所以一个特殊的排序方法:两个有序数组的合并排序。也是一个特殊的排序算法。他也很简单,所以只用记住思路就行,设置一个空数组作为排序后的数字的存放数组,然后从两个数组的第一个数字开始。如果第一个数组的值大,就把第二个数组的数字存入存放数组中,然后第二个数组的索引增加,即选择第二个数组的第二个元素;如果第二个数组的值比较大,那么就把第一个数组的值插入到存放数组中,然后第一个数组的索引增加,也就是选择第一个数组的第二个元素。以此类推,直到一方完结以后拼起来。
有了特殊的合并排序算法后,我们就可以讨论高级算法了。首先是归并排序,归并排序的思路是把一个无序数组分成两部分,分别进行排序,排完以后对返回的列表进行合并排序。上面的思路好理解,主要是一些细节需要注意。对于一个数组分成的两个子数组,也是不断采用这种方法,将子数组也划分为两个数组,分别排序,排序好以后再合并。这样无止境的分下去肯定是不行的,一定要设计调整顺序的动作,才能让数组有序,分割数组并不能让数组有序,只是让问题规模变小了。数组划分到只有两个或者一个的情况就可以进行排序了,如果想极端一点就是设置为数组长度为1时,直接返回数组,然后靠合并排序不断合并即可。这样比较省事,不然又要分长度为1,又要分长度为2,稍微麻烦。
接下来是快速排序。快速排序的思路也是把一个数组分为两个,不过他不是从位置上分,而是从某个数字开始分,大于他的分为一组,小于他的分为另一组。然后分别排序,排完序后再用简单的合并排序进行合并。说完了思路,再说一下细节,这个数字的选择不是任意的,如果你是按照位置进行选择的,那么恭喜你,很有可能你有数不清的条件语句要写,因为假设说对于某个数组来说,用这个位置的数字作为划分点会导致一个子数组为空。另一个子数组就是它本身。那么当对他的自身子数组进行划分时,又是同样的位置,又是一个空,一个自身,这样就不会停下来。这个不是算法问题,是用位置来选数字所带来的问题。所以最好的方式使用数组里面的特殊值,比如最大值,平均值等。最小值一般也不要用,也会陷入一空一自身的困境。除了这个问题,还有一个更恐怖的问题,如果这个数组里面有很多个一样的数字,或者说这个数组数字都一样,那么你选择的数字仍旧会导致无穷的分组过程中。所以为什么不试试又香又甜的归并排序呢?
来一道leetcode练手。
更高级的排序算法比如:堆排序、桶排序、基数排序、计数排序等等,之前学过,我给忘记了。
动态规划
动态规划类问题的关键点有很多,包括:
1. 确定问题的边界状态(问题的规模不可能无限缩小,但是缩小到0还是缩小到1这个问题很重要,对于编辑距离问题,缩小到0是递推的基础。如果问题规模缩小到1,就会导致无法解决,哪怕有递推公式也无法解决。)
2. 确定问题规模逐渐扩大时的变化公式(这一步往往是比较困难的,因为很难想到当前状态与之前的哪些状态有关,有的是跟上一步有关,有的是跟之前所有的有关,有的只是跟之前一定范围内的有关。)
以经典的编辑距离问题为例,编辑距离算法被数据科学家广泛应用,是用作机器翻译和语音识别评价标准的基本算法。刚见到这一题,一头雾水,虽然只有三个操作,但是每个操作的具体发生位置和对象都不确定,动作空间很大。给我两个单词,我自己都数不明白要用几步才能把两个字符串变成一样的,更别提操作的流程图了。
配合着答案,我才明白。首先把动作梳理为三个动作:①A插入一个字符;②B插入一个字符;③A替换一个字符;然后一种状态对应着三种前序动作,也就对应着三种前序状态,如果从某个状态变过来,那操作数肯定是要加1的。只不过又多考虑了一个细节,也就是两个字符串对应的尾字符是不是一致的,如果不一致,自然就不用多操作。
emmm,说这么多,还是有点迷糊,等我再刷一些题,彻底理清楚了,再说吧,目前阶段,先死记硬背吧。动态规划问题与强化学习问题和马尔可夫决策过程的背景很相似。