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.对称二叉树
给你一个二叉树的根节点 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(logN)。而在最坏情况下,树形成链状,空间复杂度为 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)。