文章目录

  • 递归面试算法总结
    • 1. LeetCode 剑指 Offer 07 : 重建二叉树
    • 2. LeetCode 687 : 最长同值路径
    • 3. LeetCode 面试题 08.06 : 汉诺塔问题
    • 4. LeetCode 894 : 所有可能的满二叉树
    • 5. LeetCode 面试题 17.12 : BiNode
    • 6. LeetCode 783 : 二叉搜索树节点最小距离
  • 回溯面试算法总结
    • 1. LeetCode 79 : 单词搜索
    • 2. LeetCode 131 : 分割回文串
    • 3. LeetCode 面试题 08.08 : 有重复字符串的排列组合
    • 4. LeetCode 39 : 组合总和
    • 5. LeetCode 40 : 组合总和 II
    • 6. LeetCode 面试题 08.07 : 无重复字符串的排列组合
    • 7. LeetCode 47 : 全排列 II
    • 8. LeetCode 1079 : 活字印刷
  • 总结

递归面试算法总结

通常用递归实现的代码比用循环实现的代码简洁,且也更加容易。如过面试没有特殊要求,则可以优先考虑用递归的方法编写程序。
递归虽然有简洁的优点,但也有显著的缺点。递归是函数调用自身,而函数调用自身是有时间和空间消耗的;同时递归中有很多计算是重复的,对性能有很大的影响。尤其要注意递归有可能引起调用栈溢出。

1. LeetCode 剑指 Offer 07 : 重建二叉树

LeetCode 剑指 Offer 07

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

/** 1* LeetCode 剑指 Offer 07 : 重建二叉树* https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/*/
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{if(preorder.empty() || inorder.empty()){return NULL;}TreeNode* root = new TreeNode(preorder[0]);int mid = distance(begin(inorder), find(inorder.begin(), inorder.end(), preorder[0]));vector<int> leftPre(preorder.begin()+1, preorder.begin()+mid+1);vector<int> rightPre(preorder.begin()+mid+1, preorder.end());vector<int> leftIn(inorder.begin(), inorder.begin()+mid);vector<int> rightIn(inorder.begin()+mid+1, inorder.end());root->left = buildTree(leftPre, leftIn);root->right = buildTree(rightPre, rightIn);return root;
}

2. LeetCode 687 : 最长同值路径

LeetCode 687

题目:给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。
注意:两个节点之间的路径长度由它们之间的边数表示。

/** 2* LeetCode 687 : 最长同值路径* https://leetcode-cn.com/problems/longest-univalue-path/*/
int Length;
int arrowLength(TreeNode* root)
{if(root == NULL)return 0;int left = arrowLength(root->left);int right = arrowLength(root->right);int arrowLeft = 0, arrowRight = 0;if(root->left != NULL && root->left->val == root->val)arrowLeft += left + 1;if(root->right != NULL && root->right->val == root->val)arrowRight += right + 1;Length = max(Length, arrowLeft + arrowRight);return max(arrowLeft, arrowRight);
}
int longestUnivaluePath(TreeNode* root)
{Length = 0;arrowLength(root);return Length;
}

3. LeetCode 面试题 08.06 : 汉诺塔问题

LeetCode 面试题 08.06

题目:在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。
请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。
你需要原地修改栈。

/** 3* LeetCode 面试题 08.06 : 汉诺塔问题* https://leetcode-cn.com/problems/hanota-lcci/*/
void move(int n, vector<int>& A, vector<int>& B, vector<int>& C)
{if(n == 1){C.push_back(A[0]);A.pop_back();return;}move(n-1, A, C, B);    // 将A上面n-1个通过C移到BC.push_back(A[0]);     // 将A最后一个移到CA.pop_back();          // 这时,A空了move(n-1, B, A, C);    // 将B上面n-1个通过空的A移到C
}
void hanota(vector<int>& A, vector<int>& B, vector<int>& C)
{int n = A.size();move(n, A, B, C);
}

4. LeetCode 894 : 所有可能的满二叉树

LeetCode 894

题目:满二叉树是一类二叉树,其中每个结点恰好有 0 或 2 个子结点。
返回包含 N 个结点的所有可能满二叉树的列表。 答案的每个元素都是一个可能树的根结点。
答案中每个树的每个结点都必须有 node.val=0。
你可以按任何顺序返回树的最终列表。

/** 4* LeetCode 894 : 所有可能的满二叉树* https://leetcode-cn.com/problems/all-possible-full-binary-trees/*/
vector<TreeNode*> allPossibleFBT(int N)
{if(N%2 == 0)return {};if(N == 1)return {new TreeNode(0)};vector<TreeNode*> ans;for(int lef = 1; lef + 1 < N; lef++){vector<TreeNode*> left = allPossibleFBT(lef);vector<TreeNode*> right = allPossibleFBT(N-1-lef);for(TreeNode* l : left){for(TreeNode* r : right){TreeNode *root = new TreeNode(0);root->left = l;root->right = r;ans.push_back(root);}}}return ans;
}

5. LeetCode 面试题 17.12 : BiNode

LeetCode 面试题 17.12

题目:二叉树数据结构TreeNode可用来表示单向链表(其中left置空,right为下一个链表节点)。实现一个方法,把二叉搜索树转换为单向链表,要求依然符合二叉搜索树的性质,转换操作应是原址的,也就是在原始的二叉搜索树上直接修改。
返回转换后的单向链表的头节点。
注意:本题相对原题稍作改动

/** 5* LeetCode 面试题 17.12 : BiNode* https://leetcode-cn.com/problems/binode-lcci/*/
void inorderTraversal(TreeNode* root, TreeNode* &cur)
{//中序遍历if(root){inorderTraversal(root->left, cur);cur->right = root; //将此节点赋给cur的右子树root->left = NULL; //将此节点的左子树赋值NULLcur = root; //更新inorderTraversal(root->right, cur);}
}
TreeNode* convertBiNode(TreeNode* root)
{TreeNode* head = new TreeNode(-1);TreeNode* cur = head;inorderTraversal(root, cur);return head->right;
}

6. LeetCode 783 : 二叉搜索树节点最小距离

LeetCode 783

题目:给定一个二叉搜索树的根节点 root,返回树中任意两节点的差的最小值。

/** 6* LeetCode 783 : 二叉搜索树节点最小距离* https://leetcode-cn.com/problems/minimum-distance-between-bst-nodes/*/
// 在二叉搜索树中,中序遍历会将树中节点按数值大小顺序输出。只需要遍历计算相邻数的差值,取其中最小的就可以了。
int _pre, _res;
bool _flag = true;
void inorder(TreeNode* root)
{if(root == NULL)return;inorder(root->left);if(!_flag){_res = min(_res, root->val - _pre);}_pre = root->val;_flag = false;inorder(root->right);
}
int minDiffInBST(TreeNode* root)
{_res = INT_MAX;inorder(root);return _res;
}

回溯面试算法总结

回溯算法实际上一个类似枚举的搜索尝试过程。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。

1. LeetCode 79 : 单词搜索

LeetCode 79

题目:给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

/** 1* LeetCode 79 : 单词搜索* https://leetcode-cn.com/problems/word-search/*/
vector<vector<int> > dirs = {{-1,0},{0,1},{1,0},{0,-1}};
bool dfs(vector<vector<char>>& board, string& word, int id, int dx, int dy, vector<vector<bool> >& visited)
{if(id == word.size()-1){return word[id] == board[dx][dy];}if(word[id] == board[dx][dy]){for(int i = 0; i < 4; i++){visited[dx][dy] = true;int ndx = dx + dirs[i][0];int ndy = dy + dirs[i][1];if(ndx >= 0 && ndx < board.size() && ndy >= 0 && ndy < board[0].size() && (!visited[ndx][ndy]) && dfs(board, word, id+1, ndx, ndy, visited)){return true;}}visited[dx][dy] = false;}return false;
}
bool exist(vector<vector<char>>& board, string word)
{if(board.size() == 0 || board[0].size() == 0){return false;}if(word.empty()){return true;}vector<vector<bool> > visited(board.size(), vector<bool>(board[0].size(), false));for(int i = 0; i < board.size(); i++){for(int j= 0; j < board[i].size(); j++){if(dfs(board, word, 0, i, j, visited)){return true;}}}return false;
}

2. LeetCode 131 : 分割回文串

LeetCode 131

题目:给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: “aab”
输出:
[
[“aa”,“b”],
[“a”,“a”,“b”]
]

/** 2* LeetCode 131 : 分割回文串* https://leetcode-cn.com/problems/palindrome-partitioning/*/
bool isPalindrome(string s)
{int first = 0;int end = s.size()-1;while(first < end){if(s[first++] != s[end--])return false;}return true;
}
void helper(string& s, int pos, vector<string>& path, vector<vector<string> >& result)
{if(pos == s.size()){result.push_back(path);return ;}for(int i = pos; i < s.size(); i++){if(isPalindrome(s.substr(pos, i-pos+1))){path.push_back(s.substr(pos, i-pos+1));helper(s, i+1, path, result);path.pop_back();}}
}
vector<vector<string>> partition(string s)
{vector<string> path;vector<vector<string> > result;helper(s, 0, path, result);return result;
}

3. LeetCode 面试题 08.08 : 有重复字符串的排列组合

LeetCode 面试题 08.08

题目:有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。
示例1:
输入:S = “qqe”
输出:[“eqq”,“qeq”,“qqe”]
示例2:
输入:S = “ab”
输出:[“ab”, “ba”]
提示:
字符都是英文字母。
字符串长度在[1, 9]之间。

/** 3* LeetCode 面试题 08.08 : 有重复字符串的排列组合* https://leetcode-cn.com/problems/permutation-ii-lcci/*/
void backtrack(const int len, map<char, int>& rec, string pre, vector<string>& res)
{if(pre.size() == len){res.push_back(pre);return;}auto iter = rec.begin();for(; iter != rec.end(); iter++){if(iter->second){(iter->second)--;backtrack(len, rec, pre + iter->first, res);(iter->second)++;}}return;
}
vector<string> permutation(string S)
{vector<string> res;map<char, int> rec;for(int i = 0; i < S.size(); i++){if(rec.count(S[i])) {rec[S[i]]++;} else {rec[S[i]] = 1;}}backtrack(S.size(), rec, "", res);return res;
}

4. LeetCode 39 : 组合总和

LeetCode 39

题目:给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入:candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入:candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
提示:
1 <= candidates.length <= 30
1 <= candidates[i] <= 200
candidate 中的每个元素都是独一无二的。
1 <= target <= 500

/** 4* LeetCode 39 : 组合总和* https://leetcode-cn.com/problems/combination-sum/*/
void backtrack(vector<int>& candidates, int target, int id, vector<int>& item, vector<vector<int> >& res)
{if(target < 0){return;}if(target == 0){res.push_back(item);return;}for(int i = id; i < candidates.size(); i++){item.push_back(candidates[i]);backtrack(candidates, target-candidates[i], i, item, res);item.pop_back();}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target)
{vector<vector<int> > res;if(candidates.empty()){return res;}vector<int> item;backtrack(candidates, target, 0, item, res);return res;
}

5. LeetCode 40 : 组合总和 II

LeetCode 40

题目:给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]

/** 5* LeetCode 40 : 组合总和 II* https://leetcode-cn.com/problems/combination-sum-ii/*/
void backtrack2(vector<int>& candidates, int start, int target, vector<int>& item, vector<vector<int>> & res)
{if(target < 0)return;if(target == 0){res.push_back(item);return;}for(int i = start; i < candidates.size(); i++){if(i > start && candidates[i] ==candidates[i - 1])continue;item.push_back(candidates[i]);backtrack2(candidates, i+1, target - candidates[i], item, res);item.pop_back();}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{vector<vector<int>> res;vector<int> item;sort(candidates.begin(),candidates.end());backtrack2(candidates,0,target,item,res);return res;
}

6. LeetCode 面试题 08.07 : 无重复字符串的排列组合

LeetCode 面试题 08.07

题目:无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。
示例1:
输入:S = “qwe”
输出:[“qwe”, “qew”, “wqe”, “weq”, “ewq”, “eqw”]
示例2:
输入:S = “ab”
输出:[“ab”, “ba”]
提示:
字符都是英文字母。
字符串长度在[1, 9]之间。

/** 6* LeetCode 面试题 08.07 : 无重复字符串的排列组合* https://leetcode-cn.com/problems/permutation-i-lcci/*/
// method 1
vector<string> permutation(string S)
{vector<string> res;dfs(S, 0, res);return res;
}
void dfs(string& S, int index, vector<string>& res)
{if(index == S.size()){res.push_back(S);return;}for(int i = index; i < S.size(); ++i){swap(S[i], S[index]);dfs(S, index + 1, res);swap(S[i], S[index]);}
}// method 2
vector<string> permutation(string S)
{sort(S.begin(), S.end());vector<string> res;res.emplace_back(S);while(next_permutation(S.begin(), S.end()))res.emplace_back(S);return res;
}// method 3
vector<string> permutation(string S)
{vector<string> res;if(S.size() == 0){return res;}vector<bool> vis(S.size(), false);backtrack(S, "", vis, res);return res;
}
void backtrack(string& S, string item, vector<bool>& vis, vector<string>& res)
{if(S.size() == item.size()){res.push_back(item);} else {for(int i = 0; i < vis.size(); i++){if(!vis[i]){item += S[i];vis[i] = true;backtrack(S, item, vis, res);item.pop_back();vis[i] = false;}}}
}

7. LeetCode 47 : 全排列 II

LeetCode 47

题目:给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]

/** 7* LeetCode 47 : 全排列 II* https://leetcode-cn.com/problems/permutations-ii/*/
void generate(vector<int>& nums, int index, vector<int>& item, vector<bool>& vis, vector<vector<int> >& res)
{if(index == nums.size()){res.push_back(item);return;}for(int i = 0; i < nums.size(); i++){if(vis[i])continue;if((i > 0) && (nums[i-1] == nums[i]) && (!vis[i-1]))continue;item.push_back(nums[i]);vis[i] = true;generate(nums, index+1, item, vis, res);item.pop_back();vis[i] = false;}
}
vector<vector<int>> permuteUnique(vector<int>& nums)
{vector<vector<int> > res;if(nums.empty())return res;vector<bool> vis(nums.size(), false);vector<int> item;sort(nums.begin(),nums.end());generate(nums, 0, item, vis, res);return res;
}

8. LeetCode 1079 : 活字印刷

LeetCode 1079

题目:你有一套活字字模 tiles,其中每个字模上都刻有一个字母 tiles[i]。返回你可以印出的非空字母序列的数目。
注意:本题中,每个活字字模只能使用一次。
示例 1:
输入:“AAB”
输出:8
解释:可能的序列为 “A”, “B”, “AA”, “AB”, “BA”, “AAB”, “ABA”, “BAA”。
示例 2:
输入:“AAABBC”
输出:188
提示:
1 <= tiles.length <= 7
tiles 由大写英文字母组成

/** 8* LeetCode 1079 : 活字印刷* https://leetcode-cn.com/problems/letter-tile-possibilities/*/
int mres;
void dfs(string& tiles, vector<bool>& vis)
{for(int i = 0; i < tiles.size(); i++){if((i > 0) && (tiles[i] == tiles[i-1] && !vis[i-1]))continue;if(!vis[i]){vis[i] = true;mres++;dfs(tiles, vis);vis[i] = false;}}
}
int numTilePossibilities(string tiles)
{mres = 0;if(tiles.empty())return mres;sort(tiles.begin(), tiles.end());vector<bool> vis(tiles.size(), false);dfs(tiles, vis);return mres;
}

总结

以上是递归和回溯相关面试算法题目汇总,个别题目也给出了解题思路和注释。
所有代码都可以去我的GitHub网站查看,后续也将继续补充其他算法方面的相关面试题目。

递归和回溯相关面试算法总结相关推荐

  1. LeetCode算法题8:递归和回溯1

    文章目录 前言 回溯算法: 一.合并两个有序链表(简单,可略过) 迭代遍历 一开始没有想到的递归解法 二.反转链表 迭代遍历(头插法): 递归: 三.组合 回溯: 四.全排列 回溯(交换): 回溯: ...

  2. 面试算法基础及编程 第四弹 (字符串、数值类、或其他常见相关)

    // # -*- coding:utf-8 -*- // # @Author: Mr.chen(ai-chen2050@qq.com) // # @Date: 2018-08-18 21:06:30 ...

  3. LeetCode算法题14:递归和回溯2

    文章目录 前言 一.全排列II 仿照全排列(n 叉树) 剪枝(去掉重复的结果) 二.组合总和 一.初始解法(n 叉树): 1,采用 Set 去重 2,在递归搜索的时候去重(推荐解法) 初始解法的遍历过 ...

  4. 【算法】递归|迷宫回溯问题|八皇后问题

    [算法]递归|迷宫回溯问题|八皇后问题   迷宫回溯问题,要用动态的眼光来看待这个递归算法. package com.serein.recursion;/*** @author baichuan* @ ...

  5. 数独算法-递归与回溯

    1.概述 数独(Sudoku)是一种运用纸.笔进行演算的逻辑游戏.玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个粗线宫内的数字均含1-9,不重复. 1)终盘 ...

  6. 基于C++的递归和回溯国际象棋女王安全算法

    资源下载地址:https://download.csdn.net/download/sheziqiong/85722216 递归和回溯 目标与要求 熟悉递归的基本思想 能够设计自己的递归函数. 关键是 ...

  7. 数据结构与算法(二):排序(递归、回溯、数论、插入、希尔、归并、选择、冒泡、快排、贪心、动态规划)

    算法排序:递归.回溯.数论.插入.希尔.归并.选择.冒泡.快排.贪心.动态规划 数论思想:利用数学公式或者定理或者规律求解问题: 算法思想中最难的点:递归+动态规划:树论:二叉树,红黑树 思考题: 微 ...

  8. 算法思想之递归分治回溯

    参考文档 递归思想 思想 描述 递归 当需要重复地多次计算相同的问题,通常可以采用递归或循环.递归是在一个函数内部调用这个函数自身. 递归的本质是把一个问题分解成两个或多个小问题.(注:当多个小问题存 ...

  9. 链表排序c++代码_[链表面试算法](一) 链表的删除-相关题型总结(6题)

    在数据结构的最高层抽象里,只有两种结构,数组和链表.这两种结构,是所有其他数据结构实现的基础.队列和栈,可以用链表和数组来实现.图,可以用邻接表和邻接矩阵来实现,其中,邻接表就是链表,邻接矩阵就是数组 ...

最新文章

  1. 传授“带权重的负载均衡实现算法”独家设计思路!
  2. JAVA_OA管理系统(二)番外篇:IoC原理
  3. 【C/C++ string】之strcpy函数
  4. css家用电器,家用电器
  5. Linux驱动编程 step-by-step (三) 字符设备中 重要的数据结构
  6. 使用electron脚手架electron-vue
  7. 4.2)深度卷积网络:实例研究
  8. IOS UI UITableView
  9. mysql 支持gbk_MySQL不支持GBK编码的解决方法
  10. 乐视android版本怎么升级,乐视网android手机客户端升级推出V2.0版
  11. mybatis plus 动态创建表和字段_mybatis-plus maven代码生成器
  12. 浅谈JS各种宽高(clientHeight、scrollHeight、offsetHeight等)
  13. Android | 判断App处于前台还是后台的方案
  14. 2018国内VR游戏现状
  15. Win 10 无法锁屏,快捷键win+L失效
  16. 读书笔记:技术的本质-技术是什么,它是怎样进化的 (布莱恩•阿瑟)
  17. 基于51单片机的点阵贪吃蛇
  18. 动态改变shiro的Principal属性
  19. ubuntu虚拟机开机黑屏系列解决办法
  20. java 下载网页,图片

热门文章

  1. python 不等于None 不等于空_干货 | 健身前后的黄金饮食法则,不懂等于白练!
  2. H.迷宫,(算法选修)
  3. C语言中数组首地址和数组第一个元素的地址有什么区别
  4. Markdown 15 款顶级笔记软件测评推荐
  5. Git报错解决:remote: error: File:1f6cc8452313 157.10 MB, exceeds 100.00 MB
  6. 南阳农运会于2012年9月16日开幕
  7. 2012年9月ITbrand电信业4G技术品牌排行榜
  8. Linux驱动开发(十五)---如何使用内核现有驱动(显示屏)
  9. 怎么保存页面为html,怎样把一个网页保存到电脑上并且保存为HTML文件?
  10. wgt 增量包下载过程中断,重新下载安装显示 [-1202]manifist 文件不存在