Обмен технологиями

Алгоритм стремится вычесть сорок две записи вопросов [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

Попробуйте сначала использовать рекурсию. Core: Каковы критерии оценки осевой симметрии?

Рекурсия: позвоните себе.Повторяющаяся логика пока не найдена

  • Определить лево==право? Ввод поддерева неверен.
  • Левое поддерево идет влево, в центр, а правое поддерево идет вправо, влево, в центр. Являются ли последовательности равными? Но это для всего дерева. Ввод поддерева также неверен.

Идея 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

Резюме [Осесимметричное двоичное дерево]:

  • Это все еще обход, но разница в следующем:Оба поддерева должны быть пройдены одновременно. . Неправильно проводить рекурсию глубоко в какое-либо поддерево.
  • Условия сравнения объектов для определения истинности: оба пусты или значения равны; Остальные ложные.
  • Также невозможно рекурсивно пройти по любому поддереву, поскольку порядок левой и правой частей различен.
  • Это не обход уровня. Если вам нужно последовательно перемещаться по слоям: получите результаты каждого слоя и измените их, чтобы увидеть, равны ли они. Как следует (не рекомендуется), все приведенные выше ответы очень хороши.
/**
 * 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.Поддерево другого дерева】

тема

Вам даны два корня и подкорень двоичных деревьев.Проверьте, содержит ли root и имеет ли subRootТа же структура и значения узлов поддерево. Если присутствует, возвращает true; в противном случае возвращает false.

Поддерево бинарного дерева включает в себя узел дерева и все узлы-потомки этого узла. дерево также можно рассматривать как поддерево самого себя.

Пример 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)Но его надо найти в корнеРавен значению корневого узла subRoot. 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

Полное текстовое резюме

Ядро: одновременное перемещение двух деревьев для определения объекта сравнения. Выполните рекурсивную реализацию.

Никакой глубокий обход дерева не даст сравнения обеих сторон объекта.

(Исправление приветствуется, при перепечатке указывайте источник)