我正在参加「掘金·启航计划」
之前一直追求去研究各种框架,研究各种经典的解决方案,对基础知识看的却是挺少的,倒不是觉得基础不重要,而是因为基础知识往往都非常枯燥,一时半会又看不出来什么效果的,经常就是兴趣来了买本书,但是没看多少内容就放弃了。前些天看了下左耳听风这个专栏,感受颇深,其实道理大家都懂,只是把枯燥的事情坚持做下去的人十之一二。
下半年准备先把effective java和常见的算法先过看一遍,后续再把网络、操作系统以及设计模式相关的知识都再看看,如果大家感觉也有焦虑或者不知道后面干啥的时候,可以多看看大佬们的分析,不要只顾着焦虑了,到最后发现啥都没做🤣。
学习的内容
最近是刚开始看算法,所以先是把之前看过的排序算法看了一遍,像冒泡排序、插入排序、选择排序都比较基础,就不拿出来写了,想和大家分享一下 归并排序、快速排序,不过介绍归并排序之前本章先聊一聊分而治之,因为是基础知识,所以算法大佬们其实是不用继续看的🤪。
1. 分而治之
分而治之(divide and conquer,D&C)并不是一种算法,而是一种使用递归来处理问题的方案,他的原理我感觉就是将大的问题拆分成同类型的小问题,直至无法拆分。这里是看了算法图解里面的两个例子,觉得还是有助于理解的。
示例1:就是有一块长度和宽度不一致的土地,有什么方法,能够将大的土地拆分成多个小的正方形,并且保证正方形尽可能的大呢,首先看下面这个图
对于上面这个50*25m的长方形来说,只要从中间切一次,就可以满足条件,然后可以分成两个25 * 25m的正方形,那如果更加不规律的长度和宽度呢
对于上面这种长度和宽度切割一次不能满足要求,这里有个理论知识要说一下,对于第一次拆分出来的240*400部分,只要我们继续往下面拆分,一旦剩下的图形满足:长度是宽度的整数倍,就说明满足了我们的题目要求,这个理论不需要大家去证实,就把他当做一个法则就行。
从上面我们可以看出,每一次拆分都是将大的图形拆分成n个正方形+ 0/1个长方形,直至我们拆分后的图形全部都是正方形为止,不难发现,其实每一次做的事情都是一样的,只是拆分图形的大小不一致而已,对于这种问题,就可以使用分治的思想。
分治思想的处理过程一般是使用递归来完成,分治的处理过程主要是包括下面几步:
- 找出基线条件,就是上面例子说的长度是宽度的整数倍时,停止拆分
- 不断将大的问题分解成结构和原问题相似的子问题,例如上面这个例子单看处理问题的方式,每一次都是同样的,直至满足基线条件
2.使用数组举例
下面给出一个具体的实例,就是如何计算下面这个数组的和,如果不使用循环,还有什么其他方式可以做到呢?
int[] arr = {1,2,3};
首先,我们可以想一下,什么样的数据我们可以直接得到他的和,如果只有0或1个数据的时候我们是不是就能直接得到他的和了呢,第一次接触的小伙伴肯定是有点难以理解的,可以先看下面这个图示就会非常的清楚这个过程。
步骤分析:
- 先将1+ 2+ 3 拆分成两部分,第一部分 单个数字1 ,第二部分为2 + 3
- 第二部分的 2 + 3不满足基线条件,于是继续拆分,拆解为 2 + 3
- 当再次准备拆解的时候发现3只有一个数据,满足基线条件,停止拆分
- 将最简单的子问题向上合并,在合并每一个子问题时对其做相加处理,最终得到我们的答案
3.分治的总结
我们这里就可以对分治的思想做一个总结,分治是一个解决问题的思想,一般使用递归这种编程技巧来处理具体逻辑,一般处理步骤有一下几步:
- 判断原问题是否能够拆分成相同类型的子问题,并且经过拆分后能够满足基线条件
- 当拆分成最小子问题,可以直接求得该子问题的最终解,也就是基线条件(3不需要计算就可以直接得到sum())
- 将子问题合并成原问题,合并时只需要简单的操作即可完成,不能过于复杂
如果满足这种条件,就可以考虑采用分治的思想来处理
总结
本章基本都是理论知识,其实刚开始刷算法题,还是挺慢的,有些东西没有掌握技巧又太绕,像写递归的时候,最近看了一个大佬写的,用推导公式的方式去写递归(有可能大家都是这么做的,只有我不知道🤣),还是容易让人接受的,后面再拿出来分享分享,今天没有直接贴代码,只是对分治这个概念有一个初步的印象就行,后面会分享我理解的归并排序和快速排序,都是使用了这个思想来处理问题。