给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/permutations
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
回溯法 :一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解的话(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化抛弃该解,即回溯并且再次尝试。
使用标记数组来处理填过的数是一个很直观的思路,但是可不可以去掉这个标记数组呢?毕竟标记数组也增加了我们算法的空间复杂度。
答案是可以的,我们可以将题目给定的 n 个数的数组 nums[]划分成左右两个部分,左边的表示已经填过的数,右边表示待填的数,我们在递归搜索的时候只要动态维护这个数组即可。
举个简单的例子,假设我们有 [2, 5, 8, 9, 10] 这 5 个数要填入,已经填到第 3 个位置,已经填了 [8,9] 两个数,那么这个数组目前为 [8, 9 | 2, 5, 10] 这样的状态,分隔符区分了左右两个部分。假设这个位置我们要填 10 这个数,为了维护数组,我们将 2 和 10 交换,即能使得数组继续保持分隔符左边的数已经填过,右边的待填 [8, 9, 10 | 2, 5] 。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/permutations/solution/quan-pai-lie-by-leetcode-solution-2/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
vector<vector<int>> permute(vector<int>& nums) {
if(nums.empty()) return {};
// 存放最后结果
vector<vector<int>> ans;
// 存放某一个排列
vector<int> temp;
// 判断该数字是否被使用过
vector<bool> used(nums.size(),false);
// 进行递归求解
dfs(ans,temp,used,nums);
return ans;
}
void dfs(vector<vector<int>>& ans,vector<int>& temp,vector<bool>& used,
const vector<int>& nums)
{
// 如果当前排列数组的长度等于输入数组的长度
// 该排列已完成
// 将该排列的加入结果中,返回
if(temp.size()==nums.size())
{
ans.push_back(temp);
return;
}
// 循环的进行枚举所有状态
for(int i=0;i<nums.size();++i)
{
// 该数字已经选择过,跳过
if(used.at(i)) continue;
// 选择当前数字
temp.push_back(nums.at(i));
// 记录该数字已被选择
used.at(i)=true;
// 递归选择下一个数字
dfs(ans,temp,used,nums);
// 回溯,撤销当前选择
used.at(i)=false;
temp.pop_back();
}
}
晕,看来要自己去写一下“八皇后问题”了。
给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。
说明:
你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。
示例 1:
输入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
输出: 1
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
输出: 3
进阶:
如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
中序遍历二叉搜索树,在遍历的过程中,每经过一个节点将k减1,当k == 0的时候,则找到了第k小的元素(注意边界)。
void recursion(TreeNode* root,int& res,int& k)
{
if(!root)
return;
recursion(root->left,res,k);
k--;
if(k == 0)
{
res = root->val;
return;
}
recursion(root->right,res,k);
}
int kthSmallest(TreeNode* root, int k) {
int res;
recursion(root,res,k);
return res;
}
关于进阶那块,我觉得可以思考一下伸展树:伸展树,据说比AVL树要简单一些
手植这棵自顶向下伸展树,何时亭亭如盖呢?