搜索树
例1 判断搜索树
给你一个二叉树的根节点
root
,判断其是否是一个有效的二叉搜索树。有效 二叉搜索树定义如下:
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
解1:暴力深搜,左每个节点值小于根,且左为搜索树
class Solution {
public:
bool cmp(TreeNode* child,int val,bool op){
bool flag=true;
if(child!=nullptr){
if(op)flag=flag&&(child->val<val)&&cmp(child->left,val,op)&&cmp(child->right,val,op);
else flag=flag&&(child->val>val)&&cmp(child->left,val,op)&&cmp(child->right,val,op);
}
return flag;
}
bool isValidBST(TreeNode* root) {
// if(root->left==nullptr&&root->right==nullptr)
bool flag=true;
if(root->left!=nullptr)
flag= flag&&cmp(root->left,root->val,1)&&isValidBST(root->left);
if(root->right!=nullptr)
flag= flag&&cmp(root->right,root->val,0)&&isValidBST(root->right);
return flag;
}
};
解2:动态范围
class Solution {
public:
bool cmp(TreeNode* child,long long lrgn,long long rrgn){
if(child==nullptr)return true;
if(child->val<=lrgn||child->val>=rrgn)return false;
return cmp(child->left,lrgn,child->val)&&cmp(child->right,child->val,rrgn);
}
bool isValidBST(TreeNode* root) {
return cmp(root, LONG_MIN, LONG_MAX);
}
};
解3:搜索二叉树中序遍历递增有序,用栈求出中序序列并比较栈顶与上一个值
class Solution {
public:
bool isValidBST(TreeNode* root) {
stack<TreeNode*> stack;
long long inorder = (long long)INT_MIN - 1;
while (!stack.empty() || root != nullptr) {
while (root != nullptr) {
stack.push(root);
root = root -> left;
}
root = stack.top();
stack.pop();
// 如果中序遍历得到的节点的值小于等于前一个 inorder,说明不是二叉搜索树
if (root -> val <= inorder) {
return false;
}
inorder = root -> val;
root = root -> right;
}
return true;
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/validate-binary-search-tree/solutions/230256/yan-zheng-er-cha-sou-suo-shu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
例2 全排列
给定一个不含重复数字的数组
nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
解1 暴力深搜,时间复杂度很高
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
if(nums.size()==1)return {{nums[0]}};
if(nums.size()==2)return {{nums[0],nums[1]},{nums[1],nums[0]}};
vector<vector<int>> result;
for(auto i:nums){
vector<int> tmp=nums;
auto index=find(tmp.begin(),tmp.end(),i);
tmp.erase(index);
vector<vector<int>> resultTmp=permute(tmp);
for(auto j:resultTmp){
j.push_back(i);
result.push_back(j);
}
}
return result;
}
};
解2 回溯,利用上一步结果
解1dfs一步步组装,递归空间深度很大,且有重复分支(每得出一个结果都要从头组装)。
解2可以理解为利用前一步组装的结果(既定前缀),再选择元素填下一个位置,填完一次后回溯(通过弹出已填位置)。
因此回溯函数里的参数是:当前排列ans(需要填),nums数组(选择需要填进去的元素)
填的位置:ans的末尾;
填的元素:nums分为两部分,前ans.size()个为已填进去的元素,每次取nums的ans.size()位置的元素填,通过交换元素将下一个选择放到ans.size()位置
class Solution {
public:
void swap(int a, int b,vector<int>& nums){
int tmp=nums[a];
nums[a]=nums[b];
nums[b]=tmp;
}
void backtrack(vector<int>& nums,vector<int>& ans,vector<vector<int>>& resultBox){
if(ans.size()==nums.size()){
resultBox.push_back(ans);
return;
}
int index=ans.size();
for(int i=index;i<nums.size();i++){
swap(i,index,nums);
ans.push_back(nums[index]);
backtrack(nums,ans,resultBox);
ans.pop_back();
swap(i,index,nums);
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<int> ans;
vector<vector<int>> resultBox;
backtrack(nums,ans,resultBox);
return resultBox;
}
};
组合
例1 电话号码的字母组合
给定一个仅包含数字
2-9
的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
class Solution {
public:
string dict[8]={"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
void backtrack(int depth,string curr,int h,vector<string>& result,string digits){
if(curr.length()==h)result.push_back(curr);
if(depth>=h)return;
int digit=(digits[depth]-'0')-2;
int n=(dict[digit]).length();
for(int i=0;i<n;i++){
curr=curr+dict[digit][i];
backtrack(depth+1,curr,h,result,digits);
curr.erase(depth,1);
}
}
vector<string> letterCombinations(string digits){
if(!digits.length())return {};
int h=digits.length();
vector<string> result;
backtrack(0,"",h,result,digits);
return result;
}
};
例2 组合总和
给你一个 无重复元素 的整数数组
candidates
和一个目标整数target
,找出candidates
中可以使数字和为目标数target
的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates
中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。对于给定的输入,保证和为
target
的不同组合数少于150
个。
回溯剪枝:
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
// if(target<=0)return {};
vector<int> tmp=candidates;
vector<vector<int>> resultBox;
for(auto i:candidates){
if(target==i){resultBox.push_back({i});continue;};
if(target<i)continue;
vector<vector<int>> tmp2=combinationSum(tmp,target-i);
if(!tmp2.empty()){
for(auto j:tmp2){
j.push_back(i);
resultBox.push_back(j);
}
}
vector<int>::iterator k = tmp.begin();
tmp.erase(k);//删除第一个元素
}
return resultBox;
}
};