기술나눔

알고리즘은 42개의 질문 레코드를 추론하려고 노력합니다. [101. 대칭 이진 트리, 100. 동일 트리, 572. 다른 트리의 하위 트리]

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

머리말

이진 트리 장에서는 이진 트리 연산 연습을 시작합니다.
레코드 42 [101. 대칭 이진 트리].
계속하다.


1. 주제 읽기

이진 트리의 루트 노드 루트를 제공합니다. 축대칭인지 확인해보세요

예시 1:
여기에 이미지 설명을 삽입하세요.

输入:root = [1,2,2,3,4,4,3]
输出:true
  • 1
  • 2

예 2:
여기에 이미지 설명을 삽입하세요.

输入:root = [1,2,2,null,3,null,3]
输出:false
  • 1
  • 2

힌트:

树中节点数目在范围 [1, 1000] 内
-100 <= Node.val <= 100
  • 1
  • 2

고급: 사용할 수 있습니다.재귀와 반복이 문제를 해결하는 두 가지 방법은 무엇입니까?


2. 깨닫도록 노력하라

아이디어 1

먼저 재귀를 사용해 보세요. 핵심: 축 대칭을 판단하는 기준은 무엇입니까?

재귀: 자신에게 전화하세요.아직 중복된 로직이 발견되지 않았습니다.

  • 왼쪽==오른쪽을 결정합니까? 하위 트리를 잘못 입력했습니다.
  • 왼쪽 하위 트리는 왼쪽, 중앙으로 이동하고 오른쪽 하위 트리는 오른쪽, 왼쪽, 중앙으로 이동합니다. 시퀀스가 동일합니까? 그러나 그것은 전체 나무에 대한 것입니다. 하위 트리에 들어가는 것도 잘못되었습니다.

아이디어 2

변경하려면 반복적인 접근 방식을 사용하세요. 레벨 순서 순회를 사용합니다.
레이어 시퀀스 결과를 얻은 후 각 레이어는 역순으로 짝수이고 동일한 것으로 판단됩니다. 그러나 두 번째 예에서는 널 포인터가 제외되기 때문에 이는 사실이 아닙니다.
아이디어가 작동하지 않습니다.

요약하다:우리는 대칭을 찾아야 한다는 것을 알고 있지만 대칭을 판단하는 통일된 표준은 없습니다.


3. 참고 아이디어

참고 링크

학습 콘텐츠

  • 축대칭: 루트 노드의 왼쪽 및 오른쪽 하위 트리가 동일하도록 뒤집어질 수 있습니까? , 비교하는 방법?
  • 설명에서 얻음올바른 생각: 이 순회에는 루트 노드의 왼쪽 하위 트리와 루트 노드의 오른쪽 하위 트리가 필요합니다.동시에 횡단 . 한 번에 두 개의 하위 트리를 순회해야만 양쪽 노드가 동일한지 여부를 판단할 수 있습니다.
    • 먼저 왼쪽 하위 트리의 왼쪽과 오른쪽 하위 트리의 오른쪽을 전달합니다. 이때 외부 노드는 동일한 것으로 판단됩니다.
    • 그런 다음 왼쪽 하위 트리의 오른쪽과 오른쪽 하위 트리의 왼쪽을 전달합니다. 이때 내부 노드는 동일한 것으로 판단됩니다.
    • 두 가지가 모두 반환된 후에는 둘 다 동시에 참이므로 대칭을 나타냅니다.
  • 왼쪽, 오른쪽, 가운데 순회 순서를 결정합니다. 왼쪽 자식을 처리한 후 오른쪽 자식을 다시 처리하고 그 결과를 중간 노드에 반환합니다.
  • 구현하려고아이디어의 부족 : 루트 노드의 왼쪽 하위 트리만 처리하여 루트 노드의 오른쪽 하위 트리의 순서가 왼쪽 하위 트리와 다른 것을 찾습니다. 순회 순서를 바꾸는 등의 방법으로는 통합 논리를 얻을 수 없습니다.

재귀적 구현

모든 댓글은 아이디어입니다.

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool iscompare(TreeNode* left,TreeNode* right){ //两边同时遍历,所以两个参数。返回是否相等,用bool类型。
        //确定终止条件
        if(!left && !right) return true;    //同时为空,可以翻转
        else if(!left && right) return false; //一个空,一个不为空。肯定不等
        else if (!right && left) return false;//一个空,一个不为空。肯定不等
        else if(left->val != right->val) return false;//都不为空,但是值不等

        //都不为空,值相等。说明可以继续进行外侧比较、内侧比较,不用return。
        bool outside = iscompare(left->left,right->right);  //同时比较,解决了左右遍历顺序不一样
        bool inside = iscompare(left->right,right->left);
        return outside && inside;   //同时返回true。才能返回true
    }
    bool isSymmetric(TreeNode* root) {
        return iscompare(root->left,root->right);
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

트리(왼쪽 하위 트리)의 순회 순서는 왼쪽 중심이고 트리(오른쪽 하위 트리)의 순회 순서는 오른쪽-왼쪽-중심입니다.

반복적인 아이디어 1

  • 루트 노드의 왼쪽 하위 트리와 루트 노드의 오른쪽 하위 트리를 동시에 처리합니다. 기존의 순회와는 다릅니다.
  • 대기열 구조 사용: 넣기비교할 두 노드가 동시에 대기열에 들어갑니다.,다시동시에 꺼내보세요 . 추출된 두 노드를 뒤집을 수 있는지 확인합니다. 따라서 왼쪽 및 오른쪽 하위 항목이 비어 있으면 이들도 대기열에 넣어야 합니다.
  • 스택 구조 사용: 동시에 두 개의 노드를 처리해야 합니다. 비교할 대상이 두 개 있습니다.동시에 넣고 동시에 꺼내세요

반복 구현 [큐 구조]

스택 구조는 동일합니다.

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(!root) return false;
        queue<TreeNode*> que;
        que.push(root->left);//放入左子树
        que.push(root->right);//放入右子树
        while(!que.empty()){
            TreeNode* left = que.front(); que.pop();//取出比较对象中的左节点
            TreeNode* right = que.front();que.pop();//取出比较对象中的右节点

            if(!left && !right){    //都是空节点
                continue;
            }else if(!left || !right || left->val != right->val){
                return false;
            }

            que.push(left->left);
            que.push(right->right);
            que.push(left->right);
            que.push(right->left);
        }
        return true;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

요약 [축대칭 이진 트리]:

  • 여전히 순회이며 차이점은 다음과 같습니다.두 하위 트리를 동시에 순회해야 함 . 하위 트리 깊은 곳까지 재귀하는 것은 올바르지 않습니다.
  • true를 결정하기 위해 객체를 비교하는 조건: 둘 다 비어 있거나 값이 동일합니다. 나머지는 거짓입니다.
  • 왼쪽과 오른쪽의 순서가 다르기 때문에 하위 트리를 재귀적으로 순회하는 것도 불가능합니다.
  • 레벨 순서 순회가 아닙니다. 레벨을 순차적으로 이동해야 하는 경우: 각 레벨의 결과를 얻은 다음, 결과가 동일한지 확인하세요. 다음과 같이(권장되지 않음) 위의 답변은 모두 매우 좋습니다.
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        vector<vector<int>> level;
        queue<TreeNode*> que;
        if(!root) return false;
        que.push(root);
        while(!que.empty()){
            int size = que.size();
            vector<int> vec;
            while(size--){
                TreeNode* cur = que.front();que.pop();
                if(cur){ //不是空节点
                    que.push(cur->left);
                    que.push(cur->right);
                    vec.push_back(cur->val);
                }else{
                    vec.push_back(INT_MIN);//因为节点的值【-100,100】。用一个最小值代表空。
                }
            }
            level.push_back(vec);
        }
        //获得层序遍历。包含空。空的数值借助INT_MIN代替。
        for(int i = 1;i < level.size();i++){
            vector<int> temp = level[i];
            reverse(temp.begin(),temp.end());
            if(temp != level[i]){
                return false;
            }
        }
        return true;

    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

질문 연습

【100.같은 나무】

1. 제목

두 이진 트리의 루트 노드 p와 q가 주어지면 두 트리가 동일한지 테스트하는 함수를 작성하세요.

나무가 두 그루라면구조적으로 동일하며 노드의 값도 동일합니다., 그들은 동일한 것으로 간주됩니다.

예시 1:

输入:p = [1,2,3], q = [1,2,3]
输出:true
  • 1
  • 2

예 2:

输入:p = [1,2], q = [1,null,2]
输出:false
  • 1
  • 2

예시 3:

输入:p = [1,2,1], q = [1,1,2]
输出:false
  • 1
  • 2

힌트:

两棵树上的节点数目都在范围 [0, 100] 内
-10^4 <= Node.val <= 10^4
  • 1
  • 2

아이디어

두 나무가 동일한지 확인합니다. 구조도 동일하고 값도 동일합니다.

  • 그렇다면 반드시두 개의 트리가 동시에 처리되는 경우에만 비교 대상이 있을 수 있습니다. . 트리에서 깊게 탐색하거나 작업을 수행하는 것은 쓸모가 없습니다.
  • [101. 대칭 이진 트리], 비교 대상과의 차이점.여기비교 개체의 왼쪽 자식은 왼쪽 자식과 비교됩니다. . 재귀 호출에 대한 매개변수가 제공됩니다.

암호

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(!p && !q) return true;  //传入节点同时为空,可以对应
        else if(!p && q) return false;//一个空,另一个不是空。不可能对应。
        else if(p && !q) return false;//一个空,另一个不是空。不可能对应。
        else if(p->val != q->val) return false;//值不等,不可能对应。

        bool leftchild = isSameTree(p->left,q->left); 
        bool rightchild = isSameTree(p->right,q->right);
        return leftchild && rightchild;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

【572.다른 트리의 하위 트리】

주제

두 개의 이진 트리 루트와 하위 루트가 제공됩니다.루트에 포함되어 있고 하위 루트에 포함되어 있는지 확인하십시오.동일한 구조 및 노드 값 하위 트리. 존재하는 경우 true를 반환하고, 그렇지 않으면 false를 반환합니다.

이진 트리의 하위 트리에는 트리의 노드와 이 노드의 모든 하위 노드가 포함됩니다. tree는 자신의 하위 트리로 볼 수도 있습니다.

예시 1:

输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true
  • 1
  • 2

예 2:

输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false
  • 1
  • 2

힌트:

root 树上的节点数量范围是 [1, 2000]
subRoot 树上的节点数量范围是 [1, 1000]
-10^4 <= root.val <= 10^4
-10^4 <= subRoot.val <= 10^4
  • 1
  • 2
  • 3
  • 4

아이디어

(1) 하위 트리는 또한 두 트리가 동일한 것으로 판단합니다. [100. 문제코드 구현]을 이용하여 평등판단을 풀 수 있습니다.
(2) 하지만 루트에서 찾아야 합니다.하위 루트 루트 노드 값과 동일 node를 하위 트리의 루트 노드로 사용합니다. 레벨 순서를 사용하여 루트를 탐색합니다.

암호

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isSame(TreeNode* rootnode,TreeNode* subRootnode){
        if(!rootnode && !subRootnode) return true;
        else if(!rootnode && subRootnode) return false;
        else if(rootnode && !subRootnode) return false;
        else if(rootnode->val != subRootnode->val) return false;

        bool leftchild = isSame(rootnode->left,subRootnode->left);
        bool rightchild = isSame(rootnode->right,subRootnode->right);
        return leftchild && rightchild;
    }
    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        //先找到和subRoot值相等的节点,才有可能相等。得遍历root找到和subRoot值相等的节点,可能作为子树的根节点

        //用层序遍历
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()){
            int size = que.size();
            while(size--){
                TreeNode* cur = que.front();que.pop();
                if(cur->val == subRoot->val){
                    bool subtree = isSame(cur,subRoot);
                    if(subtree) return true;
                }
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
        }
        return false;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

전문 요약

Core: 두 개의 트리를 동시에 탐색하여 비교 대상을 결정합니다. 재귀적 구현을 ​​수행합니다.

더 깊은 트리 순회에서는 객체의 양쪽을 비교할 수 없습니다.

(수정가능하며, 재배포시 출처를 꼭 밝혀주세요)