leetcode-master/problems/0100.相同的树.md

344 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 100. 相同的树
[力扣题目链接](https://leetcode.cn/problems/same-tree/)
给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210726172932.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210726173011.png)
# 思路
在[101.对称二叉树](https://programmercarl.com/0101.对称二叉树.html)中,我们讲到对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了**其实我们要比较的是两个树(这两个树是根节点的左右子树)**,所以在递归遍历的过程中,也是要同时遍历两棵树。
理解这一本质之后,就会发现,求二叉树是否对称,和求二叉树是否相同几乎是同一道题目。
**如果没有读过[二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html)这一篇,请认真读完再做这道题,就会有感觉了。**
递归三部曲中:
1. 确定递归函数的参数和返回值
我们要比较的是两个树是否是相互相同的,参数也就是两个树的根节点。
返回值自然是bool类型。
代码如下:
```
bool compare(TreeNode* tree1, TreeNode* tree2)
```
分析过程同[101.对称二叉树](https://programmercarl.com/0101.对称二叉树.html)。
2. 确定终止条件
**要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。**
节点为空的情况有:
* tree1为空tree2不为空不对称return false
* tree1不为空tree2为空不对称 return false
* tree1tree2都为空对称返回true
此时已经排除掉了节点为空的情况那么剩下的就是tree1和tree2不为空的时候
* tree1、tree2都不为空比较节点数值不相同就return false
此时tree1、tree2节点不为空且数值也不相同的情况我们也处理了。
代码如下:
```CPP
if (tree1 == NULL && tree2 != NULL) return false;
else if (tree1 != NULL && tree2 == NULL) return false;
else if (tree1 == NULL && tree2 == NULL) return true;
else if (tree1->val != tree2->val) return false; // 注意这里我没有使用else
```
分析过程同[101.对称二叉树](https://programmercarl.com/0101.对称二叉树.html)
3. 确定单层递归的逻辑
* 比较二叉树是否相同 传入的是tree1的左孩子tree2的右孩子。
* 如果左右都相同就返回true 有一侧不相同就返回false 。
代码如下:
```CPP
bool left = compare(tree1->left, tree2->left); // 左子树:左、 右子树:左
bool right = compare(tree1->right, tree2->right); // 左子树:右、 右子树:右
bool isSame = left && right; // 左子树:中、 右子树:中(逻辑处理)
return isSame;
```
最后递归的C++整体代码如下:
```CPP
class Solution {
public:
bool compare(TreeNode* tree1, TreeNode* tree2) {
if (tree1 == NULL && tree2 != NULL) return false;
else if (tree1 != NULL && tree2 == NULL) return false;
else if (tree1 == NULL && tree2 == NULL) return true;
else if (tree1->val != tree2->val) return false; // 注意这里我没有使用else
// 此时就是:左右节点都不为空,且数值相同的情况
// 此时才做递归,做下一层的判断
bool left = compare(tree1->left, tree2->left); // 左子树:左、 右子树:左
bool right = compare(tree1->right, tree2->right); // 左子树:右、 右子树:右
bool isSame = left && right; // 左子树:中、 右子树:中(逻辑处理)
return isSame;
}
bool isSameTree(TreeNode* p, TreeNode* q) {
return compare(p, q);
}
};
```
**我给出的代码并不简洁,但是把每一步判断的逻辑都清楚的描绘出来了。**
如果上来就看网上各种简洁的代码,看起来真的很简单,但是很多逻辑都掩盖掉了,而题解可能也没有把掩盖掉的逻辑说清楚。
**盲目的照着抄,结果就是:发现这是一道“简单题”,稀里糊涂的就过了,但是真正的每一步判断逻辑未必想到清楚。**
当然我可以把如上代码整理如下:
## 递归
```CPP
class Solution {
public:
bool compare(TreeNode* left, TreeNode* right) {
if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
else if (left->val != right->val) return false;
else return compare(left->left, right->left) && compare(left->right, right->right);
}
bool isSameTree(TreeNode* p, TreeNode* q) {
return compare(p, q);
}
};
```
## 迭代法
```CPP
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (p == NULL && q == NULL) return true;
if (p == NULL || q == NULL) return false;
queue<TreeNode*> que;
que.push(p); // 添加根节点p
que.push(q); // 添加根节点q
while (!que.empty()) { //
TreeNode* leftNode = que.front(); que.pop();
TreeNode* rightNode = que.front(); que.pop();
if (!leftNode && !rightNode) { // 若p的节点与q的节点都为空
continue;
}
// 若p的节点与q的节点有一个为空或p的节点的值与q节点不同
if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {
return false;
}
que.push(leftNode->left); // 添加p节点的左子树节点
que.push(rightNode->left); // 添加q节点的左子树节点
que.push(leftNode->right); // 添加p节点的右子树节点
que.push(rightNode->right); // 添加q节点的右子树节点
}
return true;
}
};
```
# 其他语言版本
Java
```java
// 递归法
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) return true;
else if (q == null || p == null) return false;
else if (q.val != p.val) return false;
return isSameTree(q.left, p.left) && isSameTree(q.right, p.right);
}
}
```
```java
// 迭代法
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null) return true;
if(p == null || q == null) return false;
Queue<TreeNode> que= new LinkedList<TreeNode>();
que.offer(p);
que.offer(q);
while(!que.isEmpty()){
TreeNode leftNode = que.poll();
TreeNode rightNode = que.poll();
if(leftNode == null && rightNode == null) continue;
if(leftNode == null || rightNode== null || leftNode.val != rightNode.val) return false;
que.offer(leftNode.left);
que.offer(rightNode.left);
que.offer(leftNode.right);
que.offer(rightNode.right);
}
return true;
}
}
```
Python
```python
# 递归法
class Solution:
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
if not p and not q: return True
elif not p or not q: return False
elif p.val != q.val: return False
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
```
```python
# 迭代法
class Solution:
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
if not p and not q: return True
if not p or not q: return False
que = collections.deque()
que.append(p)
que.append(q)
while que:
leftNode = que.popleft()
rightNode = que.popleft()
if not leftNode and not rightNode: continue
if not leftNode or not rightNode or leftNode.val != rightNode.val: return False
que.append(leftNode.left)
que.append(rightNode.left)
que.append(leftNode.right)
que.append(rightNode.right)
return True
```
Go
> 递归法
```go
func isSameTree(p *TreeNode, q *TreeNode) bool {
if p != nil && q == nil {
return false
}
if p == nil && q != nil {
return false
}
if p == nil && q == nil {
return true
}
if p.Val != q.Val {
return false
}
Left := isSameTree(p.Left, q.Left)
Right := isSameTree(p.Right, q.Right)
return Left && Right
}
```
JavaScript
> 递归法
```javascript
var isSameTree = function (p, q) {
if (p == null && q == null)
return true;
if (p == null || q == null)
return false;
if (p.val != q.val)
return false;
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
};
```
> 迭代法
```javascript
var isSameTree = (p, q) => {
const queue = [{ p, q }];
// 这是用{ } 解决了null的问题
while (queue.length) {
const cur = queue.shift();
if (cur.p == null && cur.q == null) continue;
if (cur.p == null || cur.q == null) return false;
if (cur.p.val != cur.q.val) return false;
queue.push({
p: cur.p.left,
q: cur.q.left
}, {
p: cur.p.right,
q: cur.q.right
});
}
return true;
};
```
TypeScript:
> 递归法-先序遍历
```typescript
function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean {
if (p === null && q === null) return true;
if (p === null || q === null) return false;
if (p.val !== q.val) return false;
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
};
```
> 迭代法-层序遍历
```typescript
function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean {
const queue1: (TreeNode | null)[] = [],
queue2: (TreeNode | null)[] = [];
queue1.push(p);
queue2.push(q);
while (queue1.length > 0 && queue2.length > 0) {
const node1 = queue1.shift(),
node2 = queue2.shift();
if (node1 === null && node2 === null) continue;
if (
(node1 === null || node2 === null) ||
node1!.val !== node2!.val
) return false;
queue1.push(node1!.left);
queue1.push(node1!.right);
queue2.push(node2!.left);
queue2.push(node2!.right);
}
return true;
};
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>