Leetcode分类解析:组合算法

本文深入探讨LeetCode中组合算法的分类,包括回溯、组合、子集、排列和分区等问题,并阐述解题策略,如递归、深度优先搜索和回溯技术的应用。通过典型问题分析,揭示了递归、DFS、BFS和回溯之间的关系,并给出了相关习题列表,帮助读者理解和掌握组合算法的精髓。
摘要由CSDN通过智能技术生成

Leetcode分类解析:组合算法

所谓组合算法就是指:在解决一些算法问题时,需要产生输入数据的各种组合、排列、子集、分区等等,然后逐一确认每种是不是我们要的解。从广义上来说,组合算法可以包罗万象,甚至排序、各种搜索算法都可以算进去。最近读《The Algorithm Design Manual》时了解到这种归类,上网一查,甚至有专门的书籍讲解,而且Knuth的巨著TAOCP的第四卷就叫组合算法,看来还真是孤陋寡闻了!于是最近着重专攻了一下Leetcode中所有相关题目,在此整理一下学习心得。题量重要,质量也重要!


1.分类地图

个人以为,以组合算法为一大类是非常好的分类方式,比目前网上看到的一些类似穷举、BFS、DFS的分类方法要清晰得多。那首先来看一下组合算法在本系列所处的位置,以及它可以细分为几小块吧:

  1. 基础结构(Fundamentals)
    1.1 数组和链表(Array&List):插入、删除、旋转等操作。
    1.2 栈和队列(Stack&Queue):栈的典型应用。
    1.3 树(Tree):构建、验证、遍历、转换。
    1.4 字符串(String):转换、搜索、运算。
  2. 积木块(Building Block)
    2.1 哈希表(Hashing)
    2.2 分治(Divide-and-Conquer)
    2.3 排序(Sorting)
    2.4 二分查找(Binary Search)
  3. 高级算法(Advanced)
    3.1 组合算法(Combinatorial Algorithm):
    - 回溯(Backtracking)
    - 组合(Combination)
    - 子集(Subset)
    - 排列(Permutation)
    - 分区(Partition)
    3.2 贪心算法(Greedy Algorithm):贪心的典型应用。
    3.3 动态规划(Dynamic Programming):广泛应用DP求最优解。
  4. 其他杂项(Misc)
    4.1 数学(Math)
    4.2 位运算(Bit Manipulation)
    4.3 矩阵(Matrix)

2.解题策略

关于组合算法的解题策略,红宝书《The Algorithm Design Manual》的第7章和第14章有详细的介绍。如果还嫌不够的话,可以参考Knuth的宏篇巨著《The Art of Computer Programming》4a卷。回溯是列举所有可能解来实现组合算法的典型技术。《The Algorithm Design Manual》除了基本问题外,还介绍了一些巧妙的剪枝技术,在此就不涉及了,还是以Leetcode为蓝本,避免跑题。


2.1 递归调用、深度搜索和回溯技术

初学时,难免对回溯、DFS、递归三者的关系理不清,感觉好像都是一个东西,其实不然。要想理清这三者的关系,先递归,再DFS/BFS,最后看一下回溯就一目了然了。


2.1.1 递归(Recursion)

递归可以用来实现各种符合递归结构的算法(正在专门写一篇递归的文章《程序设计基石:递归》)。从实现机制上来说,递归只是编程语言提供给我们的一种程序编写方式,在操作系统运行程序时用栈Frame来帮我们实现。从解决问题的方式上来说,与循环从前往后的解决问题方式类似,递归是自底向上,先得到更小问题的解,再逐步合并成大问题的解。以Leetcode习题为例,最典型的就是递归实现的Divide-and-Conquer策略,能够解决一大类问题,所以它绝不限于DFS和回溯问题。


2.1.2 深度/广度优先搜索(DFS/BFS)

而所谓的深度优先DFS、广度优先BFS,则是属于图(树)范畴的术语,特指逐步遍历图中各结点的方式。一般来说,DFS用递归实现比较方便,因为我们充分利用编程语言提供的便利,将Stack的维护问题交给OS去管理了。当然我们完全可以忽视这种遍历,自己显示用循环+Stack方式实现。而BFS则一般要用循环+Queue的方式去实现,因为没有像递归那样的简便实现机制,所以稍显麻烦一些。以Leetcode习题为例,树的前中后序遍历都属于DFS,而Level序遍历(及像ZigZag各种变种问题)都属于BFS。


2.1.3 回溯(Backtracking)

终于说到了回溯,《The Algorithm Design Manual》给出了定义:”Backtracking can be viewed as a depth-first search on an implicit graph”,用树(图)来表示递归的执行过程的话(这是很自然的研究递归的方式),回溯就是在隐式图上执行的DFS搜索来构建解的方式。所谓隐式图在第5章开头有解释:它指的就是我们不会一上来就把回溯的整个递归过程形成的树(图)完全生成出来,而是随着回溯的执行,一点点构建,有点像游戏里的打地图。其实很容易理解,因为很多问题不是要找到所有解,而是判断有解就可以结束回溯了,所以没必要走完整个搜索空间。当然,上面的定义并不绝对,为什么不用BFS呢?《The Algorithm Design Manual》的解释是:因为对大部分问题来说,执行过程树的高度不会太高

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值