跳转至

算法

关于组合问题的算法设计

昨天做了力扣编号为 2597 的算法题,需要遍历数组的所有集合,并从集合中选出符合要求的集合。了解后发现需要使用回溯算法解决,特此记录。

递归 + 回溯是一种非常强大的算法设计技巧,特别适合解决组合问题(如遍历所有子集)。它的核心思路是通过递归探索所有的可能,并通过回溯撤销选择,从而覆盖所有可能的组合。

它是如何工作的,本质上子集问题的目标是找到所有可能的自己。对于一个长度为 \(n\) 的数组,总共有 \(2n\) 个子集(包括空集)。比如 \({1, 2, 3}\) 的子集是:

\[ \{1\}、\{2\}、\{3\}、\{1, 2\}、\{1, 3\}、\{2, 3\}、 \{\} \]

回文十进制数

Tip

如果把某个数的各个数字按相反的顺序排列,得到的数和原来的数相同,则这个数就是“回文数”。譬如 123454321 就是一个回文数。

问题: 求用十进制、二进制、八进制表示都是回文数的所有数字中,大于十进制数 10 的最小值。

位运算

位操作(Bit Manipulation)是程序设计中对位模式或二进制数的一元和二元操作。在许多古老的微处理器上,位运算比加减运算略快,通常位运算比乘除法运算要快很多。在现代编程语言中,情况并非如此,很多编程语言的解释器都会基本的运算进行了优化,因此我们在实际开发中可以不必做一些编译器已经帮我们做好的优化,而就写出代码本身所要表现的意思。

动态规划

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

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

动态规划有自底向上和自顶向下两种解决问题的方式。自顶向下即记忆化递归,自底向上就是递推。

使用动态规划解决的问题有个明显的特点,一旦一个子问题的求解得到结果,以后的计算过程就不会修改它,这样的特点叫做无后效性,求解问题的过程形成了一张有向无环图。动态规划只解决每个子问题一次,具有天然剪枝的功能,从而减少计算量。

关于算法中的问题总结

在刷题的过程中遇到了一些经典问题和经典解法,我觉得很有必要对其进行归纳与总结,避免未来遇到同样的问题捉急。

递归/回溯

递归是计算机科学中的一个重要概念。它是许多其他算法和数据结构的基础。然而,对于许多初学者来说,掌握它可能是一件非常棘手的事情。

每当递归函数调用自身时,它都会将给定的问题拆解为子问题。递归调用继续进行,直到到子问题成为一个不可以拆分的、可以直接求解的最简单问题。

为了确保递归函数不会导致无限循环,它需要包含:

一个简单的基本案例(basic case)(或一些案例), 能够不使用递归来产生答案的终止方案。 一组规则,也称作递推关系(recurrence relation),可将所有其他情况拆分到基本案例。 注意,函数可能会有多个位置进行自我调用(这是分治算法)。

深度优先搜索

深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次.

因发明「深度优先搜索算法」,约翰 · 霍普克洛夫特与罗伯特 · 塔扬在1986年共同获得计算机领域的最高奖:图灵奖。

广度优先搜索

广度优先搜索算法(Breadth-First Search,缩写为 BFS),又称为宽度优先搜索,是一种图形搜索算法。简单的说,BFS 是从根结点开始,沿着树的宽度遍历树的结点。如果所有结点均被访问,则算法中止。

双指针

双指针从广义上来说,是指用两个变量在线性结构上遍历而解决的问题。狭义上说,

  • 对于数组,指两个变量在数组上相向移动解决的问题;

  • 对于链表,指两个变量在链表上同向移动解决的问题,也称为「快慢指针」问题。

二分查找

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法,可以在数据规模的对数时间复杂度内完成查找。

二分查找可以应用于数组,是因为数组具有有随机访问的特点,并且数组是有序的。

二分查找体现的数学思想是「减而治之」,可以通过当前看到的中间元素的特点推测它两侧元素的性质,以达到缩减问题规模的效果。

二分查找问题也是面试中经常考到的问题,虽然它的思想很简单,但写好二分查找算法并不是一件容易的事情。