数据结构算法题——树

leetcode-94.二叉树的中序遍历

leetcode-94.二叉树的中序遍历
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

void inorder(struct TreeNode* root, int* res, int* resSize)
{
    if(root == NULL)
        return ;
    inorder(root->left, res, resSize);
    res[(*resSize)++] = root->val;
    inorder(root->right, res, resSize);
}

int* inorderTraversal(struct TreeNode* root, int* returnSize){
    *returnSize = 0;
    int* res = (int*)malloc(sizeof(int) * 500);
    inorder(root, res, returnSize);
    return res;
}

时间复杂度:O(n),其中 n 为二叉树节点的个数。二叉树的遍历中每个节点会被访问一次且只会被访问一次。
空间复杂度:O(n)。空间复杂度取决于递归的栈深度,而栈深度在二叉树为一条链的情况下会达到 O(n) 的级别。

leetcode-95.不同的二叉搜索树 II

leetcode-95.不同的二叉搜索树 II
给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

struct TreeNode** buildTree(int start, int end, int* returnSize)
{
    if(start > end){
        (*returnSize) = 1;
        struct TreeNode** ret = malloc(sizeof(struct TreeNode*));
        ret[0] = NULL;
        return ret;
    }
    *returnSize = 0;
    struct TreeNode** allTrees = malloc(0);
    // 枚举可行根结点
    for(int i = start; i <= end; i++){
        // 获得所有可行的左子树集合
        int leftTreesSize;
        struct TreeNode** leftTrees = buildTree(start, i - 1, &leftTreesSize);

        // 获取所有可行的右子树的集合
        int rightTreesSize;
        struct TreeNode** rightTrees = buildTree(i + 1, end, &rightTreesSize);

        // 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根结点上
        for(int left = 0; left < leftTreesSize; left++){
            for(int right = 0; right < rightTreesSize; right++){
                struct TreeNode* currTree = malloc(sizeof(struct TreeNode));
                currTree->val = i;
                currTree->left = leftTrees[left];
                currTree->right = rightTrees[right];
                (*returnSize)++;
                allTrees = realloc(allTrees, sizeof(struct TreeNode*) * (*returnSize));
                allTrees[(*returnSize) - 1] = currTree;
            }
        }
        free(rightTrees);
        free(leftTrees);
    }
    return allTrees;
}

struct TreeNode** generateTrees(int n, int* returnSize){
    if(!n){
        (*returnSize) = 0;
        return NULL;
    }
    return buildTree(1, n, returnSize);
}

leetcode-98.验证二叉搜索树(中序遍历)

leetcode-98.验证二叉搜索树(中序遍历)
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。
bool inOrder(struct TreeNode* root, int** prev)
{
    if(root->left)
        if(inOrder(root->left, prev) == 0)
            return 0;
    if(*prev)
        if(root->val <= *(*prev))
            return 0;
    *prev = &root->val;
    if(root->right)
        if(inOrder(root->right, prev) == 0)
            return 0;
    return 1;
}

bool isValidBST(struct TreeNode* root){
    int *prev = NULL;
    if(!root){
        return 1;
    }
    return inOrder(root, &prev);
}

leetcode-100.相同的树

leetcode-100.相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p==NULL && q==NULL){
        return true;
    }
    else if(p==NULL || q==NULL){
        return false;
    }
    else if(p->val != q->val){
        return false;
    }
    else{
        return isSameTree(p->left, q->left) & isSameTree(p->right, q->right);
    }
}

时间复杂度:O(min(m,n)),其中 m 和 n 分别是两个二叉树的节点数。对两个二叉树同时进行深度优先搜索,只有当两个二叉树中的对应节点都不为空时才会访问到该节点,因此被访问到的节点数不会超过较小的二叉树的节点数。
空间复杂度:O(min(m,n)),其中 m 和 n 分别是两个二叉树的节点数。空间复杂度取决于递归调用的层数,递归调用的层数不会超过较小的二叉树的最大高度,最坏情况下,二叉树的高度等于节点数。

leetcode-101.对称二叉树

leetcode-101.对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

bool check(struct TreeNode* p, struct TreeNode* q)
{
    if(p==NULL && q==NULL){
        return true;
    }
    if(p==NULL || q==NULL){
        return false;
    }
    return p->val==q->val & check(p->left, q->right) & check(p->right, q->left);
}

bool isSymmetric(struct TreeNode* root){
    return check(root, root);
}

时间复杂度:这里遍历了这棵树,渐进时间复杂度为 O(n)。
空间复杂度:这里的空间复杂度和递归使用的栈空间有关,这里递归层数不超过 n,故渐进空间复杂度为 O(n)。

leetcode-102.二叉树的层序遍历

leetcode-102.二叉树的层序遍历
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
    *returnSize = 0;
    if(root == NULL)
        return NULL;
    int** result = (int**)malloc(sizeof(int*) * 10000);
    *returnColumnSizes = (int*)malloc(sizeof(int) * 10000);
    // 模拟队列
    struct TreeNode* queue[10000] = {0};
    int front = -1;
    int rear = -1;
    queue[++rear] = root;
    int level = 0;
    int n = 0;
    while(rear != front){
        n = (rear - front) % 10000;
        result[level] = (int*)malloc(sizeof(int)* n);
        (*returnColumnSizes)[level] = n;
        for(int i = 0; i < n; i++){
            struct TreeNode* tmp = queue[++front];
            result[level][i] = tmp->val;
            if(tmp->left) queue[++rear] = tmp->left;
            if(tmp->right) queue[++rear] = tmp->right;         
        }
        level++;
    }
    *returnSize = level;
    return result;
}

时间复杂度:每个点进队出队各一次,故渐进时间复杂度为 O(n)。
空间复杂度:队列中元素的个数不超过 n 个,故渐进空间复杂度为 O(n)。

leetcode-103.二叉树的锯齿形层序遍历

leetcode-103.二叉树的锯齿形层序遍历
给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

int** zigzagLevelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
    *returnSize = 0;
    if(root == NULL)
        return NULL;
    int** result = (int**)malloc(sizeof(int*) * 10000);
    *returnColumnSizes = (int*)malloc(sizeof(int) * 10000);
    struct TreeNode* queue[10000] = {0};
    int rear = -1, front = -1;
    queue[++rear] = root;
    int level = 0;
    int n = 0;
    while(rear != front){
        n = (rear - front) % 10000;
        result[level] = (int*)malloc(sizeof(int) * n);
        (*returnColumnSizes)[level] = n;
        for(int i = 0; i < n; i++){
            struct TreeNode* tmp = queue[++front];
            if(level % 2 == 0)
                result[level][i] = tmp->val;
            else
                result[level][n-1-i] =tmp->val;
            if(tmp->left)
                queue[++rear] = tmp->left;
            if(tmp->right)
                queue[++rear] = tmp->right;
        }
        level++;
    }
    *returnSize = level;
    return result;
}

时间复杂度:每个点进队出队各一次,故渐进时间复杂度为 O(n)。
空间复杂度:队列中元素的个数不超过 n 个,故渐进空间复杂度为 O(n)。

leetcode-104.二叉树的最大深度

leetcode-104.二叉树的最大深度
给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

int maxDepth(struct TreeNode* root){
    if(root == NULL)
        return 0;
    return fmax(maxDepth(root->left), maxDepth(root->right)) + 1;
}

时间复杂度:O(n),其中 n 为二叉树节点的个数。每个节点在递归中只被遍历一次。

空间复杂度:O(height),其中 height 表示二叉树的高度。递归函数需要栈空间,而栈空间取决于递归的深度,因此空间复杂度等价于二叉树的高度。

leetcode-105.从前序与中序遍历序列构造二叉树

leetcode-105.从前序与中序遍历序列构造二叉树
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

int local(int* nums, int l, int r, int x)
{
    for(int i = l; i <= r; i++){
        if(nums[i] == x)
            return i;
    }
    return -1;
}

struct TreeNode* preInorder(int * preorder, int l1, int r1, int* inorder, int l2, int r2)
{
    if(l1 > r1)
        return NULL;
    struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    int bit = local(inorder, l2, r2, preorder[l1]);
    node->val = preorder[l1];
    node->left = preInorder(preorder, l1 + 1, l1 + bit - l2, inorder, l2, bit - 1);
    node->right = preInorder(preorder, l1 + bit - l2 + 1, r1, inorder, bit + 1, r2);
    return node;
}

struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
    struct TreeNode* head;
    head = preInorder(preorder, 0, preorderSize - 1, inorder, 0, inorderSize - 1);
    return head;
}

时间复杂度:O(n),其中 n 是树中的节点个数。
空间复杂度:O(n),除去返回的答案需要的 O(n) 空间之外,我们还需要使用 O(n) 的空间存储哈希映射,以及 O(h)(其中 h 是树的高度)的空间表示递归时栈空间。这里 h < n,所以总空间复杂度为 O(n)。

leetcode-106.从中序与后序遍历序列构造二叉树

leetcode-106.从中序与后序遍历序列构造二叉树
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

struct TreeNode* postInorder(int* inorder, int l1, int r1, int* postorder, int l2, int r2)
{
    if(l1 > r1)
        return NULL;
    struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    node->val = postorder[r2];
    int idx = -1;
    for(int i = l1; i <= r1; i++){
        if(inorder[i] == postorder[r2]){
            idx = i;
            break;
        }
    }
    // 注意先右再左
    node->right = postInorder(inorder, idx + 1, r1, postorder, l2 + idx - l1, r2 - 1);
    node->left = postInorder(inorder, l1, idx - 1, postorder, l2, l2 + idx - l1 - 1); 
    return node;
}

struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int postorderSize){
    struct TreeNode* head;
    head = postInorder(inorder, 0, inorderSize - 1, postorder, 0, postorderSize - 1);
    return head;
}

时间复杂度:O(n),其中 n 是树中的节点个数。
空间复杂度:O(n)。我们需要使用 O(n)的空间存储哈希表,以及 O(h)(其中 h 是树的高度)的空间表示递归时栈空间。这里 h < n,所以总空间复杂度为 O(n)。

leetcode-107.二叉树的层序遍历 II

leetcode-107.二叉树的层序遍历 II
给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

int** levelOrderBottom(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
    int** levelOrder = malloc(sizeof(int*) * 2001);
    *returnColumnSizes = malloc(sizeof(int) * 2001);
    *returnSize = 0;
    if(!root){
        return levelOrder;
    }
    struct TreeNode** q = malloc(sizeof(struct TreeNode*) * 2001);
    int rear = 0, front = 0;
    q[rear++] = root;
    while(front < rear){
        int len = rear - front;
        int* level = malloc(sizeof(int) * len);
        (*returnColumnSizes)[*returnSize] = len;
        for(int i = 0; i < len; i++){
            struct TreeNode* node = q[front++];
            level[i] = node->val;
            if(node->left){
                q[rear++] = node->left;
            }
            if(node->right){
                q[rear++] = node->right;
            }
        }
        levelOrder[(*returnSize)++] = level;
    }
    for(int i = 0; i * 2 < *returnSize; i++){
        int* tmp1 = levelOrder[i];
        levelOrder[i] = levelOrder[(*returnSize) - i - 1];
        levelOrder[(*returnSize) - i - 1] = tmp1;
        int* tmp2 = (*returnColumnSizes)[i];
        (*returnColumnSizes)[i] = (*returnColumnSizes)[(*returnSize) - i - 1];
        (*returnColumnSizes)[(*returnSize) - i - 1] = tmp2;
    }
    return levelOrder;
}

时间复杂度:O(n),其中 n 是二叉树中的节点个数。每个节点访问一次,结果列表使用链表的结构时,在结果列表头部添加一层节点值的列表的时间复杂度是 O(1),因此总时间复杂度是 O(n)。
空间复杂度:O(n),其中 n 是二叉树中的节点个数。空间复杂度取决于队列开销,队列中的节点个数不会超过 n。

leetcode-108.将有序数组转换为二叉搜索树

leetcode-108.将有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。

struct TreeNode* buildSearchTree(int* nums, int left, int right)
{
    if(left > right){
        return NULL;
    }
    int mid = (left + right) / 2;
    struct TreeNode* root = malloc(sizeof(struct TreeNode));
    root->val = nums[mid];
    root->left = buildSearchTree(nums, left, mid - 1);
    root->right = buildSearchTree(nums, mid + 1, right);
    return root;
}

struct TreeNode* sortedArrayToBST(int* nums, int numsSize){
    return buildSearchTree(nums, 0, numsSize - 1);
}

时间复杂度:O(n),其中 n 是数组的长度。每个数字只访问一次。
空间复杂度:O(logn),其中 n 是数组的长度。空间复杂度不考虑返回值,因此空间复杂度主要取决于递归栈的深度,递归栈的深度是 O(logn)。

leetcode-109.有序链表转换二叉搜索树

leetcode-109.有序链表转换二叉搜索树
给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。

struct ListNode* getMedian(struct ListNode* left, struct ListNode* right)
{
    struct ListNode* fast = left;
    struct ListNode* slow = left;
    while(fast != right && fast->next != right)
    {
        fast = fast->next;
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}

struct TreeNode* buildTree(struct ListNode* left, struct ListNode* right)
{
    if(left == right)
        return NULL;
    struct TreeNode* root = malloc(sizeof(struct TreeNode));
    struct ListNode* mid = getMedian(left, right);
    root->val = mid->val;
    root->left = NULL;
    root->right = NULL;
    root->left = buildTree(left, mid);
    root->right = buildTree(mid->next, right);
    return root;
}

struct TreeNode* sortedListToBST(struct ListNode* head){
    return buildTree(head, NULL);
}

时间复杂度:O(nlogn),其中 n 是链表的长度。
设长度为 n 的链表构造二叉搜索树的时间为 T(n),递推式为 T(n) = 2⋅T(n/2) + O(n),根据主定理,T(n) = O(nlogn)。
空间复杂度:O(logn),这里只计算除了返回答案之外的空间。平衡二叉树的高度为 O(logn),即为递归过程中栈的最大深度,也就是需要的空间。

leetcode-110.平衡二叉树

leetcode-110.平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

// 自底向上递归
int height(struct TreeNode* root)
{
    if(root == NULL)
        return 0;
    int leftHeight = height(root->left);
    int rightHeight = height(root->right);
    if(leftHeight == -1 || rightHeight == -1 || fabs(leftHeight - rightHeight) > 1)
        return -1;
    else
        return fmax(leftHeight, rightHeight) + 1;
}

bool isBalanced(struct TreeNode* root)
{
    return height(root) >= 0;
}

时间复杂度:O(n),其中 n 是二叉树中的节点个数。使用自底向上的递归,每个节点的计算高度和判断是否平衡都只需要处理一次,最坏情况下需要遍历二叉树中的所有节点,因此时间复杂度是 O(n)。
空间复杂度:O(n),其中 n 是二叉树中的节点个数。空间复杂度主要取决于递归调用的层数,递归调用的层数不会超过 n。

leetcode-111.二叉树的最小深度

leetcode-111.二叉树的最小深度
给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明:叶子节点是指没有子节点的节点。

int minDepth(struct TreeNode* root){
    if(root == NULL)
        return 0;
    if(root->left == NULL && root->right == NULL){
        return 1;
    }
    int mn = INT_MAX;
    if(root->left){
        mn = fmin(mn, minDepth(root->left));
    }
    if(root->right){
        mn = fmin(mn, minDepth(root->right));
    }
    return mn + 1;
}

时间复杂度:O(n),其中 n 是树的节点数。对每个节点访问一次。
空间复杂度:O(h),其中 h 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O(n)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O(logn)。

leetcode-112.路径总和

leetcode-112.路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。

叶子节点 是指没有子节点的节点。

bool hasPathSum(struct TreeNode* root, int targetSum)
{
    if(root == NULL)
        return false;
    if(root->right == NULL && root->left == NULL){
        if(targetSum - root->val == 0)
            return true;
        return false;
    }
    return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
}

时间复杂度:O(n),其中 n 是树的节点数。对每个节点访问一次。
空间复杂度:O(h),其中 h 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O(n)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O(logn)。

leetcode-113.路径总和 II

leetcode-113.路径总和 II
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

int** ret;
int retSize;
int* retColSize;
int* path;
int pathSize;

void dfs(struct TreeNode* root, int targetSum)
{
    if(root == NULL)
        return ;
    path[pathSize++] = root->val;
    targetSum -= root->val;
    if(root->left == NULL && root->right == NULL && targetSum == 0){
        int* tmp = malloc(sizeof(int) * pathSize);
        memcpy(tmp, path, sizeof(int) * pathSize);
        ret[retSize] = tmp;
        retColSize[retSize++] = pathSize;
    }
    dfs(root->left, targetSum);
    dfs(root->right, targetSum);
    pathSize--;
}

int** pathSum(struct TreeNode* root, int targetSum, int* returnSize, int** returnColumnSizes){
    ret = malloc(sizeof(int*) * 2001);
    retColSize = malloc(sizeof(int) * 2001);
    path = malloc(sizeof(int) * 2001);
    retSize = pathSize = 0;
    dfs(root, targetSum);
    *returnColumnSizes = retColSize;
    *returnSize = retSize;
    return ret;
}

时间复杂度:O(N2),其中 N 是树的节点数。在最坏情况下,树的上半部分为链状,下半部分为完全二叉树,并且从根节点到每一个叶子节点的路径都符合题目要求。此时,路径的数目为 O(N),并且每一条路径的节点个数也为 O(N),因此要将这些路径全部添加进答案中,时间复杂度为 O(N2)。
空间复杂度:O(N),其中 N 是树的节点数。空间复杂度主要取决于栈空间的开销,栈中的元素个数不会超过树的节点数。

leetcode-114.二叉树展开为链表

leetcode-114.二叉树展开为链表
给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。
void flatten(struct TreeNode* root){
    struct TreeNode* cur = root;
    while(cur != NULL){
        if(cur->left != NULL){
            struct TreeNode* next = cur->left;
            struct TreeNode* pre = next;
            while(pre->right != NULL){
                pre = pre->right;
            }
            pre->right = cur->right;
            cur->left = NULL;
            cur->right = next;
        }
        cur = cur->right;
    }
}

时间复杂度:O(n),其中 n 是二叉树的节点数。展开为单链表的过程中,需要对每个节点访问一次,在寻找前驱节点的过程中,每个节点最多被额外访问一次。
空间复杂度:O(1)。

leetcode-129.求根节点到叶节点数字之和

leetcode-129.求根节点到叶节点数字之和
给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:

  • 例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。

计算从根节点到叶节点生成的 所有数字之和

叶节点 是指没有子节点的节点。

int dfs(struct TreeNode* root, int sum)
{
    if(root == NULL)
        return 0;
    sum  = sum * 10 + root->val;
    if(root -> left == NULL && root -> right == NULL)
        return sum;
    else
        return dfs(root->left, sum) + dfs(root->right,sum);
}

int sumNumbers(struct TreeNode* root)
{
    return dfs(root, 0);
}

时间复杂度:O(n),其中 n 是二叉树的节点个数。对每个节点访问一次。
空间复杂度:O(n),其中 n 是二叉树的节点个数。空间复杂度主要取决于递归调用的栈空间,递归栈的深度等于二叉树的高度,最坏情况下,二叉树的高度等于节点个数,空间复杂度为 O(n)。

leetcode-144.二叉树的前序遍历

leetcode-144.二叉树的前序遍历
给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

void preorder(struct TreeNode* root, int* res, int* resSize)
{
    if(root == NULL)
        return ;
    res[(*resSize)++] = root->val;
    preorder(root->left, res, resSize);
    preorder(root->right, res, resSize);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize){
    int *res = malloc(sizeof(int) * 2000);
    *returnSize = 0;
    preorder(root, res, returnSize);
    return res;
}

时间复杂度:O(n),其中 n 是二叉树的节点数。每一个节点恰好被遍历一次。
空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)。

leetcode-145.二叉树的后序遍历

leetcode-145.二叉树的后序遍历
给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

void postOrder(struct TreeNode* root, int* res, int* resSize)
{
    if(root == NULL)
        return ;
    postOrder(root->left, res, resSize);
    postOrder(root->right, res, resSize);
    res[(*resSize)++] = root->val;
}

int* postorderTraversal(struct TreeNode* root, int* returnSize){
    int* res = malloc(sizeof(int) * 2000);
    *returnSize = 0;
    postOrder(root, res, returnSize);
    return res;
}

时间复杂度:O(n),其中 n 是二叉搜索树的节点数。每一个节点恰好被遍历一次。
空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)。

leetcode-222.完全二叉树的节点个数

leetcode-222.完全二叉树的节点个数
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

int countNodes(struct TreeNode* root){
    if(root == NULL){
        return 0;
    }
    return countNodes(root->left) + countNodes(root->right) + 1;
}

leetcode-226.翻转二叉树

leetcode-226.翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

struct TreeNode* invertTree(struct TreeNode* root){
    if(root == NULL){
        return NULL;
    }
    struct TreeNode* l = root->left;
    struct TreeNode* r = root->right;
    l = invertTree(root->right);
    r = invertTree(root->left);
    root->left = l;
    root->right = r;
    return root;
}

时间复杂度:O(N),其中 N 为二叉树节点的数目。我们会遍历二叉树中的每一个节点,对每个节点而言,我们在常数时间内交换其两棵子树。
空间复杂度:O(N)。使用的空间由递归栈的深度决定,它等于当前节点在二叉树中的高度。在平均情况下,二叉树的高度与节点个数为对数关系,即 O(log⁡N)。而在最坏情况下,树形成链状,空间复杂度为 O(N)。

leetcode-230.二叉搜索树中第k小的元素

leetcode-230.二叉搜索树中第k小的元素
给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

int cnt = 0;
int value = 0;

void dfs(struct TreeNode* root, int k)
{
    if(root == NULL)
        return ;
    dfs(root->left, k);
    cnt++;
    if(cnt == k){
        value = root->val;
        return ;
    }
    dfs(root->right, k);
}

int kthSmallest(struct TreeNode* root, int k){
    cnt = 0;
    value = 0;
    dfs(root, k);
    return value;
}

时间复杂度:O(H+k),其中 H 是树的高度。在开始遍历之前,我们需要 O(H) 到达叶结点。当树是平衡树时,时间复杂度取得最小值 O(logN+k);当树是线性树(树中每个结点都只有一个子结点或没有子结点)时,时间复杂度取得最大值 O(N+k)。
空间复杂度:O(H),栈中最多需要存储 H 个元素。当树是平衡树时,空间复杂度取得最小值 O(logN);当树是线性树时,空间复杂度取得最大值。

leetcode-404.左叶子之和

leetcode-404.左叶子之和
给定二叉树的根节点 root ,返回所有左叶子之和。

int sumOfLeftLeaves(struct TreeNode* root){
    if(root == NULL){
        return 0;
    }
    int l = 0;
    if(root->left != NULL && root->left->left ==NULL && root->left->right == NULL){
        l = root->left->val;
    }
    return l + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);
}

时间复杂度:O(n),其中 n 是树中的节点个数。
空间复杂度:O(n)。空间复杂度与深度优先搜索使用的栈的最大深度相关。在最坏的情况下,树呈现链式结构,深度为 O(n),对应的空间复杂度也为 O(n)。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值