
递归
这里记录有价值的递归题目
哎呦,帅小伙哦
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
分治算法
回溯、分治、动态规划可以划分为一类,因为它们都会涉及递归。1)回溯算法就是一种简单粗暴的算法技巧,说白了就是一个暴力穷举算法,就考你会不会漏掉或者多算某些情况。2)动态规划是一类算法问题,肯定是让你求最值的。因为动态规划问题拥有最优子结构,可以通过状态转移方程从最小规模的子问题最优解推导出最大规模问题的最优解。3)分治算法,可以认为是一种算法思想,通过将原有问题分解成小规模的子问题,然后根据子问题的结果构造出原问题的答案。这里有点动态规划的意思,所以说运用分治算法也需要满足一些条件,你的原问题结果应该...原创 2021-05-14 14:40:49 · 120 阅读 · 0 评论 -
LeetCode 剑指Offer 26 树的子结构
class Solution { public: bool isSubStructure(TreeNode* A, TreeNode* B) { if(B == nullptr) return false;//空树不算子结构 if(A == nullptr) return false; return judge(A, B) || isSubStructure(A -> left, B) || isSubStructure(A -> rig原创 2021-05-13 12:00:22 · 84 阅读 · 0 评论 -
LeetCode 面试题04.10 检查子树
分析 递归,judge来判断t1和t2是否相同。 代码 class Solution { public: bool checkSubTree(TreeNode* t1, TreeNode* t2) { if(t2 == nullptr) return true; if(t1 == nullptr) return false; return judge(t1, t2) || checkSubTree(t1 -> left, t2) || ch.原创 2021-05-13 11:44:44 · 87 阅读 · 0 评论 -
LeetCode 面试题04.05 合法的二叉搜索树
分析 要解决这道题首先我们要了解二叉搜索树有什么性质可以给我们利用,由题目给出的信息我们可以知道:如果该二叉树的左子树不为空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;它的左右子树也为二叉搜索树。 这启示我们设计一个递归函数 helper(root, lower, upper) 来递归判断,函数表示考虑以 root 为根的子树,判断子树中所有节点的值是否都在 (l,r) 的范围内(注意是开区间)。如果 root 节点的值 val 不在 (l.原创 2021-05-13 11:20:41 · 115 阅读 · 0 评论 -
LeetCode 450 删除二叉搜索树中的节点
分析 二叉搜索树的递归框架如下: TreeNode* BST(TreeNode* root, int target){ if(root != nullptr) return root; if(root -> val == target){ //找到目标,该做什么 }else if(root -> val < target){ root -> right = BST(root -> right, target); }else{ root -> lef.原创 2021-04-16 16:35:42 · 91 阅读 · 0 评论 -
LeetCode 538 把二叉树转换成累加树
分析 BST相关的问题,不是利用BST做小右大的特性提升算法效率,就是利用中序遍历的特性满足题目要求。这道题目我们利用中序遍历,但是是按照右中左的顺序访问的,而且会在外部维护一个sum来记录遍历到当前结点的和。代码如下: 代码 class Solution { public: int sum;//记录和 TreeNode* convertBST(TreeNode* root) { sum = 0; traverse(root); retur.原创 2021-04-15 09:59:04 · 86 阅读 · 0 评论 -
LeetCode 652 寻找重复的子树
分析 二叉树的题目需要判断使用前序中序还是后序,怎么判断呢?这就需要根据题意,思考一个二叉树结点需要做什么。比如这道题目,需要注意两点: 1)以我为根的这棵二叉树(子树)长啥样 2)以其他结点为根的子树长什么样子 **根据树的序列化和反序列化,已经知道,如果唯一的确定一棵二叉树,这里我们使用后序遍历。**只需要将每棵二叉树的序列化后的s放入到一个map中即可(在放入之前,看一看有没有其他的树和要放入的树相同)。 代码 class Solution { public: map<string,.原创 2021-04-14 23:48:18 · 154 阅读 · 0 评论 -
LeetCode 297 二叉树的序列化和反序列化
分析 需要注意的是,一般情况下,单单前序遍历是不能还原二叉树结构的,因为缺少空指针的信息,至少要得到前中后序遍历中的两种才能还原二叉树。但是我们可以记录空指针的位置,这样就可以唯一确定一棵二叉树。后序遍历也可以完成,但是需要注意的是,中序遍历是不可以的,因为反序列化要求先拿到root节点,中序遍历做不到这一点。这道题目除了前后序遍历可以解决,层次遍历也是可以解决的。这里不写代码了。 代码 //前序遍历代码 class Codec { public: // Encodes a tree to a.原创 2021-04-14 16:40:27 · 108 阅读 · 0 评论 -
LeetCode 783二叉搜索树节点最小距离
分析 因为是二叉搜索树,所以满足条件的结点肯定是中序遍历后相邻的结点,递归地进行中序遍历,使用pre记录前面结点的值,这样遍历完整棵树就可以得到任意结点最小距离。 代码 class Solution { public: int min; int minDiffInBST(TreeNode* root) { min = INT_MAX; int pre = -100001; traverse(root, pre); retu.原创 2021-04-13 15:48:52 · 115 阅读 · 0 评论 -
LeetCode 222 完全二叉树的节点个数
分析 如果是一棵普通的二叉树,返回树中结点个数的代码如下: int countNodes(TreeNode* root){ if(null == root) return 0; return 1 + countNodes(root -> left) + countNodes(root -> right); } 如果是一棵满二叉树,结点总数就和树的高度呈指数关系,时间复杂度是O(logN * logN)( 思考为什么): int countNodes(TreeNode* root){ .原创 2021-04-13 13:19:35 · 102 阅读 · 0 评论 -
使用递归方法判断回文单链表
分析 这道题的难点在于,单链表无法倒着遍历,无法使用双指针技巧。容易想到的思路就是把原始链表反转存入一条新的链表,然后比较这两条链表是否相同。**其实也可以借助二叉树后序遍历的思路,不需要显式反转原始链表也可以倒序遍历链表。**因为链表也兼具这样的递归结构,链表其实也可以有前序遍历和后序遍历。 void traverse(ListNode* head){ if(head == nullptr) return; traverse(head -> next); cout << hea.原创 2021-04-13 12:05:06 · 348 阅读 · 0 评论 -
K个一组反转链表
分析 这个题具有递归性质,什么叫递归性质?假设我们每2个一组反转链表。我们设法把前2个节点反转,那么后面的那些节点也是一条链表,而且规模(长度)比原来这条链表小,这就是子问题。因此我们只需要把链表的前2个节点反转,然后让反转后的前两个节点中最后一个节点的next指向reverseKGroup(子问题)返回的指针即可。需要注意这道题目的base case是链表节点个数小于k的时候返回head。 代码 /** * Definition for singly-linked list. * struct L.原创 2021-04-12 12:15:43 · 119 阅读 · 0 评论 -
LeetCode 114 二叉树展开为链表
分析 这个问题可以分为两步,1)将root的左子树和右子树拉平 2)将root的右子树接到左子树的下方,然后将整个左子树作为整个右子树。锻炼递归 代码 void flatten(TreeNode* root){ if(nullptr == root) return; //将左右子树拉成一条链表 flatten(root -> left); flatten(root -> right); TreeNode* .原创 2021-04-10 16:28:29 · 85 阅读 · 0 评论 -
LeetCode 116 填充每个节点的下一个右侧节点指针
分析 这道题也可以使用层次遍历,递归的代码更简洁。递归算法的关键要明确函数的定义,相信这个定义,而不要跳进递归细节。 代码 class Solution { public: Node* connect(Node* root) { if(nullptr == root) return nullptr; connectTwo(root -> left, root -> right); return root; } //连接.原创 2021-04-10 16:11:24 · 97 阅读 · 0 评论 -
递归反转单链表
1,反转整个链表 reverse函数的作用是反转以head节点为头结点的链表,并返回反转后的头结点指针。reverse(head -> next)这个会进行递归,但是不要跳进递归(你的脑袋能压几个栈呀?),而是根据刚才的函数定义,来弄清楚这段代码会产生的后果。 ListNode* reverse(ListNode* head){ if(head -> next == nullptr) return head; ListNode* last = reverse(head -> next)原创 2021-04-09 16:23:15 · 373 阅读 · 0 评论 -
LeetCode 322 零钱兑换
分析 这是一道完全背包的题目,但是我们这里只使用暴力法求解,目的是锻炼递归思维。暴力法其实是N叉树的后序遍历。 代码 class Solution { public: int coinChange(vector<int>& coins, int amount) { return dp(coins, coins.size(),amount); } int dp(vector<int>& coins, in.原创 2021-04-09 15:11:30 · 88 阅读 · 0 评论 -
LeetCode 779 第K个语法符号
分析 这道题是一个递归的题目。 当N==1的时候,返回false; 当K大于2的N-2的方时候,kthGrammar(N, K)的值是由kthGrammar(N, K - 2 的N-2次方)取反得到的; 当K小于2的N-2的方时候,kthGrammar(N, K)的值和kthGrammar(N - 1, K)的值相同。 代码 class Solution { public: int kthGrammar(int N, int K) { if(helper(N, K)) retur.原创 2021-04-02 11:14:18 · 124 阅读 · 0 评论