大多数人都有过这样的体会:刷过一系列算法题,并且对常见的解题思路已经了然于胸,可一段时间后,以前的算法题再次变得很陌生。
这一方面是因为很多算法的解题思路巧妙但不直观,另一方面也是因为平时的编码工作并不经常涉及这些巧妙的算法。
为了快速回忆起遗忘的常见算法,这篇“蜂博客”罗列了常见算法的核心思想。
“LeetCode”是一个比较完善的在线题库,有以下几个优势:
暴力解法
暴力解法是最直观的解题思路,但是效率一般不如其他的方法。暴力解法的主体思想是将问题解法的可能性进行分类枚举,并用大量循环结构解出问题的解。本人建议,对于陌生的算法题,可先用暴力解法得出问题的答案,再思考是否有其他更高效的解法。
深度递归解法
树的深度遍历包括:前序遍历、中序遍历和后序遍历。三种遍历都可以通过递归,将大问题化解成小问题,并以边界条件终止。深度递归解法类似深度遍历,利用递归将问题拆解,找到终止逻辑,并通过递归缩小问题范围(如同深度遍历,每次递归处理的树都是上次递归的子树)。
f(n)
问题为例。动态规划解法会依次求出f(1)
到f(n-1)
的所有值,再推导出f(n)
的值。而深度递归解法并不会记录f(1)
到f(n-1)
的值,而是
利用递归直接求出f(n)
的值。C++
实现可参考GitHub。
{49 38 65 97}
初始数据为例子,选取49
为比较数字,经过一次归并后,得到两组数据{38} 49 {97 65}
。继续为此两组数据进行分组,直到分组中的数据只有一个。采用左右逼近比较的方法,进行一次分组。字符串
对字符串的底层数据结构和数组是一样的,常见的操作如:寻找回文子串,逆序等。大部分问题可以先从暴力解法入手(一般是多层循环),再考虑是否可以优化(如:动态规划,KMP等)。
Stack
完成了对单向链表的重组操作。需要注意的是,在对链表操作中,会存在数据个数单双数两种情况,可以先分两种情况考虑,再看看能不能合并。