搜索与回溯算法(简单)
一、剑指 Offer 26. 树的子结构
代码如下(示例):
【C++代码】
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isSubStructure(TreeNode* A, TreeNode* B) {
if(!A ||!B) return false;
if(isPart(A,B)) return true;
return isSubStructure(A->left,B)||isSubStructure(A->right,B);
}
bool isPart(TreeNode*p1,TreeNode *p2){
if(!p2) return true;
if(!p1||p1->val !=p2->val) return false;
return isPart(p1->left,p2->left)&&isPart(p1->right,p2->right);
}
};
【分析】
若树B是树A的子结构,则子结构的根节点可能为树A的任意一个节点。因此,判断树B是否是A的子结构,需要完成以下两步骤工作:
- 前序遍历树A中的每个节点nA;(对应于isSubStucture(A,B));
- 判断树A中以nA为根节点的子树是包含树B.(对应于函数isPart(A,B))
【算法流程】:
名词规定:树A的根节点记作节点A,树B的根节点称为节点B
isPart(A,B)函数
bool isPart(TreeNode*p1,TreeNode *p2){
if(!p2) return true;
if(!p1||p1->val !=p2->val) return false;
return isPart(p1->left,p2->left)&&isPart(p1->right,p2->right);
}
//1、终止条件:
//1、当节点B为空,说明树B已经匹配完成
//2、当节点A为空,说明已经越过树A叶子节点,即匹配失败,返回false
//3、当节点A和B的值不同:说明匹配失败,返回false
//2、返回值
//1、判断A和B的左子节点是否相等,即isPart(p1->left,p2->left)
//2、判断A和B的右子节点是否相等,即isPart(A->right,B->right);
isSubStructure(A,B)函数:
//1、 特例处理:当树A为空或树B为空时,直接返回false;
//2、 返回值:若树B是树A的子结构,则必须满足以下三种情况之一,因此用或连接
//1、 以节点A为根节点的子树包含树B,对应isPart(A,B);
//2、 树B是树A左子树的子结构,对应isSubStructure(A->left,B)
//3、 树B是树A右子树的子结构,对应isSubStructure(A->right,B);
bool isSubStructure(TreeNode* A, TreeNode* B) {
if(!A ||!B) return false;
if(isPart(A,B)) return true;
return isSubStructure(A->left,B)||isSubStructure(A->right,B);
}
二、剑指 Offer 27. 二叉树的镜像
【C++代码】
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
if(!root) return nullptr;
mirrorTree(root->left);
mirrorTree(root->right);
swap(root->left,root->right);
return root;
}
};
【分析】
三、剑指 Offer 28. 对称的二叉树
【C++代码】
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(!root) return true;
return dfs(root->left,root->right);
}
bool dfs(TreeNode*p,TreeNode*q){
if(!p||!q) return !q&&!p;
if(p->val !=q->val) return false;
return dfs(p->left,q->right) &&dfs(p->right,q->left);
}
};
[分析]
解题思路:
对称二叉树定义:对于树中任意两个对称节点L和R,一定有
1、L->val = R->val;即对称节点值相等
2、L->>left->val = r->right->val;即L的左子节点和R的右子节点对称;
3、L->right->val = R->left->val;即L的右子节点和R的左子节点对称。
根据以上规律,考虑从顶至底层递归,判断每对节点是否对称,从而判断树是否为对称二叉树。
【算法流程】:
/*isSymmetric(root):
特例处理:若根节点root为空,则直接返回true.
返回值:即dfs(root->left,root->right);
*/
bool isSymmetric(TreeNode* root) {
if(!root) return true;
return dfs(root->left,root->right);
}
/*dfs(left,right):
终止条件:
当left和right同时越过叶节点:此树从顶至底的节点都对称,因此返回ture;
当left和right中有一个越过叶节点:此树不对称
当节点L值不等于节点R值:此树不对称
递推工作:
判断两节点L->left和R->right是否对称,即dfs(L->left,R->right);
判断两节点L->right和R->left是否对称,即dfs(L->right,R->left);
返回值 :两节点都对称时,才是对称树,因此用与逻辑&&连接
*/
bool dfs(TreeNode*p,TreeNode*q){
if(!p||!q) return !q&&!p;
if(p->val != q->val) return false;
return dfs(p->left,q->right) &&dfs(p->right,q->left);
}