leetcode 2020/09 每日一题

leetcode 2020/9 每日一题

2020/9/11: 组合总和 III

问题 中等

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:

所有数字都是正整数。
解集不能包含重复的组合。
示例 1:

输入: k = 3, n = 7
输出: [[1,2,4]]
示例 2:

输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]

my way

回溯法

循环加递归,还有改进空间,有重复计算过程

class Solution {
public:
    vector<vector<int>> combinationSum(int k, int n,int m){
        vector<vector<int>> tmp;
        if(k==1){
            for(int i=m;i<=9;i++)
                if(i==n){
                    vector<int> tmp1;
                    tmp1.push_back(i);
                    tmp.push_back(tmp1);
                }
            
            return tmp;
        }
        for(int i=m;i<=10-k;i++){
            vector<vector<int>> tmp0;
            tmp0 = combinationSum(k-1,n-i,i+1) ;
            for(int j=0;j<tmp0.size();j++){
                tmp0[j].insert(tmp0[j].begin(),i);
            }
            tmp.insert(tmp.end(),tmp0.begin(),tmp0.end());
        }
        return tmp;
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        vector<vector<int>> tmp;
        for(int i=1;i<=10-k;i++){
            vector<vector<int>> tmp0;
            tmp0 = combinationSum(k-1,n-i,i+1);
            for(int j=0;j<tmp0.size();j++){
                tmp0[j].insert(tmp0[j].begin(),i);
            }
            tmp.insert(tmp.end(),tmp0.begin(),tmp0.end());
        }
        return tmp;
        
    }

};
  • 时间复杂度 O(k!)
  • 空间复杂度 空间复杂度:O(M)。temp 数组的空间代价是 O(k),递归栈空间的代价是 O(M),故空间复杂度为 O(M + k) = O(M)

官方解答

思路类似于我的方法,都是寻找所有组合方法一个个判断。

class Solution{
public:
    vector<int> temp;
    vector<vector<int>> ans;
    
    void dfs(int cur,int n, int k, int sum){
        if(temp.size() + (n-cur +1)<k || temp.size() >k){
            return;
        }
        if(temp.size() == k && accumulate(temp.begin(),temp.end(),0) == sum){
            ans.push_back(temp);
            return;
        }
        temp.push_back(cur);
        dfs(cur+1,n,k,sum);
        temp.pop_back();
        dfs(cur+1,n,k,sum);
    }
    
    vector<vector<int>> combinationSum3(int k,int n){
        dfs(1,9,k,n);
        return ans;
    }
     
 }
  • 时间复杂度:O({M \choose k} \times k)O(( kM)×k),其中 M 为集合的大小,本题中 M 固定为 9。一共有 M \choose k( kM ) 个组合,每次判断需要的时间代价是 O(k)。
  • 空间复杂度:O(M)。temp 数组的空间代价是 O(k),递归栈空间的代价是 O(M),故空间复杂度为 O(M + k) = O(M)

2020/9/12:二叉树的层平均值

问题 简单

给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。

示例 1:

输入:
3
/
9 20
/
15 7
输出:[3, 14.5, 11]
解释:
第 0 层的平均值是 3 , 第1层是 14.5 , 第2层是 11 。因此返回 [3, 14.5, 11] 。

my way

使用队列层次遍历二叉树,并使用另一个队列作为flag,标志每一层的结束。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        queue<TreeNode*> s;
        queue<int> flag;
        vector<double> result;
        double sum_cur=0;
        double l = 0;
        s.push(root);
        flag.push(0);
        while(!s.empty()){
            int tmp=flag.front();
            TreeNode* cur = s.front();
            s.pop();
            flag.pop();
            sum_cur+=cur->val;
            l++;
            if(flag.empty() || tmp!= flag.front()){
                result.push_back(sum_cur/l);
                l=0;
                sum_cur=0;
            }
            if(cur->left!=NULL){
                s.push(cur->left);
                flag.push(!tmp);
            }
            if(cur->right!=NULL){
                s.push(cur->right);
                flag.push(!tmp);
            }    
        }
        return result;
    }
};
  • 时间复杂度O(n), 其中n是二叉树中的节点个数。
  • 空间复杂度O(n)

官方解答之 广度优先遍历

类似于我的方法。

比我的更好,不需要flag,直接将每一层的队列节点全部取出,需要在遍历每一层之前获取每一层的size。

class Solution{
public:
     vector<double> averageOfLevels(TreeNode* root) {
        auto averages = vector<double>();
        auto q = queue<TreeNode*>();
        q.push(root);
        while (!q.empty()) {
            double sum = 0;
            int size = q.size();
            for (int i = 0; i < size; i++) {
                auto node = q.front();
                q.pop();
                sum += node->val;
                auto left = node->left, right = node->right;
                if (left != nullptr) {
                    q.push(left);
                }
                if (right != nullptr) {
                    q.push(right);
                }
            }
            averages.push_back(sum / size);
        }
        return averages;
    }
};
  • 时间复杂度:O(n),其中 n 是二叉树中的节点个数
  • 空间复杂度:O(n)

官方解答之 深度优先遍历

class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        auto counts = vector<int>();
        auto sums = vector<double>();
        dfs(root, 0, counts, sums);
        auto averages = vector<double>();
        int size = sums.size();
        for (int i = 0; i < size; i++) {
            averages.push_back(sums[i] / counts[i]);
        }
        return averages;
    }

    void dfs(TreeNode* root, int level, vector<int> &counts, vector<double> &sums) {
        if (root == nullptr) {
            return;
        }
        if (level < sums.size()) {
            sums[level] += root->val;
            counts[level] += 1;
        } else {
            sums.push_back(1.0 * root->val);
            counts.push_back(1);
        }
        dfs(root->left, level + 1, counts, sums);
        dfs(root->right, level + 1, counts, sums);
    }
};

  • 时间复杂度:O(n),其中 nn 是二叉树中的节点个数。
    深度优先搜索需要对每个节点访问一次,对于每个节点,维护两个数组的时间复杂度都是 O(1),因此深度优先搜索的时间复杂度是 O(n)。
    遍历结束之后计算每层的平均值的时间复杂度是 O(h),其中 hh 是二叉树的高度,任何情况下都满足 h≤n。
    因此总时间复杂度是 O(n)。

  • 空间复杂度:O(n),其中 n 是二叉树中的节点个数。空间复杂度取决于两个数组的大小和递归调用的层数,两个数组的大小都等于二叉树的高度,递归调用的层数不会超过二叉树的高度,最坏情况下,二叉树的高度等于节点个数

2020/9/14: 二叉树的中序遍历

问题

给定一个二叉树,返回它的中序 遍历。

示例:

输入: [1,null,2,3]
1

2
/
3

输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?

递归解法

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> result ;
    vector<int> inorderTraversal(TreeNode* root) {
        if(root==NULL)
            return result;
        dfs(root);
        return result;
    }
    void dfs(TreeNode* root){
       if(root==NULL)
            return ;
        dfs(root->left);
        result.push_back(root->val);
        dfs(root->right);
        return;
    }
};
  • 时间复杂度O (n) ,n为二叉树的节点数
  • 空间复杂度O(n), (不包括结果占用的空间) 递归的次数,最坏情况下为n

迭代

非递归算法

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> stk;
        while(root != nullptr || !stk.empty()){
            while(root!=nullptr){
                stk.push(root);
                root = root->left;
            }
            root = stk.top();
            stk.pop();
            res.push_back(root->val);
            root = root->right;
        }
        return res;
    }
};
  • 时间复杂度:O(n),其中 n 为二叉树节点的个数。二叉树的遍历中每个节点会被访问一次且只会被访问一次。
  • 空间复杂度:O(n)。空间复杂度取决于栈深度,而栈深度在二叉树为一条链的情况下会达到 O(n) 的级别。

Morris中序遍历

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        TreeNode *predecessor = nullptr;

        while (root != nullptr) {
            if (root->left != nullptr) {
                // predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
                predecessor = root->left;
                while (predecessor->right != nullptr && predecessor->right != root) {
                    predecessor = predecessor->right;
                }
                
                // 让 predecessor 的右指针指向 root,继续遍历左子树
                if (predecessor->right == nullptr) {
                    predecessor->right = root;
                    root = root->left;
                }
                // 说明左子树已经访问完了,我们需要断开链接
                else {
                    res.push_back(root->val);
                    predecessor->right = nullptr;
                    root = root->right;
                }
            }
            // 如果没有左孩子,则直接访问右孩子
            else {
                res.push_back(root->val);
                root = root->right;
            }
        }
        return res;
    }
};
  • 时间复杂度:O(n),其中 n 为二叉搜索树的节点个数。Morris 遍历中每个节点会被访问两次,因此总时间复杂度为O(2n)=O(n)。
  • 空间复杂度:O(1)。

2020/9/18:全排列 II

问题 中等

给定一个可包含重复数字的序列,返回所有不重复的全排列。

示例:

输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]

我的程序

莫得,我没做出来。

搜索回溯

class Solution{
    vector<int> vis;
public:
    void backtrack(vector<int>& nums,vector<int>>& ans,int idx,vector<int>& perm){
		if(idx == nums.size()){
            ans.emplace_back(perm);
            return;
        }
        for(int i=0;i<(int)nums.size();++i){
            if(vis[i] || (i>0 && nums[i] == nums[i-1] && !vis[i-1])){
                continue;
            }
            perm.emplace_back(nums[i]);
            vis[i] = 1;
            backtrack(nums,ans,idx+1,perm);
            vis[i] = 0;
            perm.pop_back();
        }
        
    }
    vector<vector<int>> permuteUnique(vector<int>& nums){
        vector<vector<int>> ans;
        vector<int> perm;
        vis.resize(nums.size());
        sort(nums.begin().nums.end());
        backtrack(nums,ans,0,perm);
        return ans;
    }
}
    
  • 时间复杂度O(n*n!),其中n为序列的长度
  • 空间复杂度O(n)

2020/9/20:子集

问题

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

my way

回溯搜索法

class Solution {
public:
    vector<vector<int>> result;
    vector<vector<int>> subsets(vector<int>& nums) {

        vector<int> tmp;
        backtrack(tmp,nums,0);
        return result;
    }
    void backtrack(vector<int> tmp,vector<int>& nums,int t){
        if(nums.begin()+t == nums.end()){
            result.push_back(tmp);
            return;
        }
        backtrack(tmp,nums,t+1);
        tmp.push_back(*(nums.begin()+t));
        backtrack(tmp,nums,t+1);
        return;
    }
};
  • 时间复杂度
  • 空间复杂度

不会算。。。。

迭代法实现子集枚举

class Solution {
public:
    vector<int> t;
    vector<vector<int>> ans;

    vector<vector<int>> subsets(vector<int>& nums) {
        int n = nums.size();
        for (int mask = 0; mask < (1 << n); ++mask) {
            t.clear();
            for (int i = 0; i < n; ++i) {
                if (mask & (1 << i)) {
                    t.push_back(nums[i]);
                }
            }
            ans.push_back(t);
        }
        return ans;
    }
}

  • 时间复杂度:O(n*2^n)一共 2^n个状态,每种状态需要O(n) 的时间来构造子集。
  • 空间复杂度:O(n)。即构造子集使用的临时数组 t 的空间代价

递归法实现自己枚举

class Solution {
public:
    vector<int> t;
    vector<vector<int>> ans;

    void dfs(int cur, vector<int>& nums) {
        if (cur == nums.size()) {
            ans.push_back(t);
            return;
        }
        t.push_back(nums[cur]);
        dfs(cur + 1, nums);
        t.pop_back();
        dfs(cur + 1, nums);
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        dfs(0, nums);
        return ans;
    }
};
  • 时间复杂度:O(n * 2 ^ n) )。一共 2^n个状态,每种状态需要O(n) 的时间来构造子集。
  • 空间复杂度 O(n)。临时数组 tt 的空间代价是 O(n),递归时栈空间的代价为 O(n)。

2020/9/21:把二叉搜索树转换为累加树

问题

给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。

例如:

输入: 原始二叉搜索树:
5
/
2 13

输出: 转换为累加树:
18
/
20 13

反序中序遍历

class Solution {
public:
    int sum = 0;

    TreeNode* convertBST(TreeNode* root){
        if(root != nullptr){
            convertBST(root->right);
            sum+=root->val;
            root->val=sum;
            convertBST(root->left);
        }
     	return root;
    }
};
  • 时间复杂度O(n),n是二叉树的节点数
  • 空间复杂度O(n), 为递归过程中的栈的开销,平均情况下O(logn),最坏情况下为链状,O(n).

2020/09/23:合并二叉树

**问题 ** 简单

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

示例 1:

输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/
4 5
/ \ \
5 4 7
注意: 合并必须从两个树的根节点开始。

深度优先搜索

class Solution {
public:

    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if(t1==nullptr)
            return t2;
        if(t2==nullptr)
            return t1;
        TreeNode* root=new TreeNode();
        root->val=t1->val+t2->val;
        root->right=mergeTrees(t1->right,t2->right);
        root->left=mergeTrees(t1->left,t2->left);
        return root;
    }
};
  • 时间复杂度O(min(m,n)) m, n为2个树各自节点个数
  • 时间复杂度O(min(m,n)

2020/9/26: 路径总和 II

问题

给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

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

示例:
给定如下二叉树,以及目标和 sum = 22,

          5
         / \
        4   8
       /   / \
      11  13  4
     /  \    / \
    7    2  5   1

返回:

[
[5,4,11,2],
[5,8,4,5]
]

深度优先搜索

class Solution {
public:
    vector<vector<int>> result;
    vector<int> cur_num;
    int cur_sum=0;
    void dfs(TreeNode* root, int sum){
        if(root==nullptr)
            return;
        cur_num.push_back(root->val);
        cur_sum+=root->val;
        if(cur_sum==sum && root->right==nullptr && root->left==nullptr){
            result.push_back(cur_num);
        }
        else{
            dfs(root->left,sum);
            dfs(root->right,sum);
        }
        cur_num.pop_back();
        cur_sum-=root->val;
        return;              
    }
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
            dfs(root,sum);
            return result;
        }
};
  • 时间复杂度O(n^2) ,n为节点数,在最坏情况下,树的上半部分为链状,下半部分为完全二叉树,并且从根节点到每一个叶子节点的路径都符合题目要求。此时,路径的数目为 O(N),并且每一条路径的节点个数也为 O(N),因此要将这些路径全部添加进答案中,时间复杂度为 O(N^2)
  • 空间复杂度O(n), path空间,最坏情况下n

2020/9/27: 二叉搜索树的最近公共祖先

问题 简单

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

示例 1:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
示例 2:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

说明:

所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉搜索树中。

一次遍历

根据二叉搜索树的特点可知,从根节点开始遍历,若qp的值都小于当前节点的值,则当前节点指向左子树,反之则指向右子树;若当前节点的值位于中间位置,则当前节点应当是公共祖先节点。

class Solution {
public:

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        TreeNode* curnode=root;
        while(true){
            if(curnode->val > p->val && curnode->val > q->val){
                curnode = curnode->left;
            }
            else if(curnode->val < p->val && curnode->val < q->val){
                curnode = curnode->right;
            }
            else
                break;
        }
        return curnode;

    }

};
  • 时间复杂度O(n) n为节点数
  • 空间复杂度O(1)

2020/9/28:填充每个节点的下一个右侧节点指针 II

问题 中等

给定一个二叉树

struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

img

进阶:

你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。

示例:

输入:root = [1,2,3,4,5,null,7]
输出:[1,#,2,3,#,4,5,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。

提示:

树中的节点数小于 6000
-100 <= node.val <= 100

广度优先遍历

使用了一个队列空间

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;
    Node* next;

    Node() : val(0), left(NULL), right(NULL), next(NULL) {}

    Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}

    Node(int _val, Node* _left, Node* _right, Node* _next)
        : val(_val), left(_left), right(_right), next(_next) {}
};
*/

class Solution {
public:
    Node* connect(Node* root) {
        queue<Node*> tmp;
        if(root==nullptr)
            return root;
        tmp.push(root);
        while(!tmp.empty()){
            int len = tmp.size();
            for(int i=0;i<len;i++){
                Node* cur = tmp.front();
                tmp.pop();
                if(cur->left!=nullptr)
                    tmp.push(cur->left);
                if(cur->right!=nullptr)
                    tmp.push(cur->right);
                if(i==len-1){
                    cur->next = NULL;
                }
                else{
                    cur->next = tmp.front();
                }
            }
        }
        return root;
    }
};
  • 时间复杂度O(n);
  • 空间复杂度O(n);

使用已建立的next指针

降低空间复杂度。。。

不会做,看不懂!!!!!!!!!!

先抄一段代码,CV大法好。

具体来说:

从根节点开始。因为第 00 层只有一个节点,不需要处理。可以在上一层为下一层建立 \rm nextnext 指针。该方法最重要的一点是:位于第 xx 层时为第 x + 1x+1 层建立 \rm nextnext 指针。一旦完成这些连接操作,移至第 x + 1x+1 层为第 x + 2x+2 层建立 \rm nextnext 指针。
当遍历到某层节点时,该层节点的 \rm nextnext 指针已经建立。这样就不需要队列从而节省空间。每次只要知道下一层的最左边的节点,就可以从该节点开始,像遍历链表一样遍历该层的所有节点。

public:
    void handle(Node* &last, Node* &p, Node* &nextStart) {
        if (last) {
            last->next = p;
        } 
        if (!nextStart) {
            nextStart = p;
        }
        last = p;
    }

    Node* connect(Node* root) {
        if (!root) {
            return nullptr;
        }
        Node *start = root;
        while (start) {
            Node *last = nullptr, *nextStart = nullptr;
            for (Node *p = start; p != nullptr; p = p->next) {
                if (p->left) {
                    handle(last, p->left, nextStart);
                }
                if (p->right) {
                    handle(last, p->right, nextStart);
                }
            }
            start = nextStart;
        }
        return root;
    }
};

  • 时间复杂度:O(N)。分析同「方法一」。
  • 空间复杂度:O(1)

2020/9/29:二叉树的后序遍历

问题 中等

给定一个二叉树,返回它的 后序 遍历。

示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [3,2,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:
    vector<int> result;
    vector<int> postorderTraversal(TreeNode* root) {
        postorder(root);
        return result;
    }
    void postorder(TreeNode* root){
        if(root==nullptr)
            return;
        postorder(root->left);
        postorder(root->right);
        result.push_back(root->val);
        return;
    }

};
  • 时间复杂度O(n), n为节点数
  • 空间复杂度O(n), 递归隐式栈占用的空间,平均情况下为 O(log n),最坏情况下树呈现链状,为 O(n)。

迭代

隐式栈变成显式栈

后序遍历 左-右-中 , 可以改成中-右-左,最后翻转下

/**
 * 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:

    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        if(root==nullptr)
            return result;
        stack<TreeNode*> tmp;
        tmp.push(root);
        while(!tmp.empty()){
            TreeNode* cur = tmp.top();
            tmp.pop();
            result.push_back(cur->val);
            if(cur->left!=nullptr){
                tmp.push(cur->left);
            }
            if(cur->right!=nullptr){
                tmp.push(cur->right);
            }
        }
        reverse(result.begin(),result.end());
        return result;
    }
};
  • 时间复杂度O(n)
  • 空间复杂度O(n)

2020/9/30:二叉搜索树中的插入操作

问题 中等

给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据保证,新值和原始二叉搜索树中的任意节点值都不同。

注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。

例如,

给定二叉搜索树:

    4
   / \
  2   7
 / \
1   3

和 插入的值: 5
你可以返回这个二叉搜索树:

     4
   /   \
  2     7
 / \   /
1   3 5

或者这个树也是有效的:

     5
   /   \
  2     7
 / \   
1   3
     \
      4

提示:

给定的树上的节点数介于 0 和 10^4 之间
每个节点都有一个唯一整数值,取值范围从 0 到 10^8
-10^8 <= val <= 10^8
新值和原始二叉搜索树中的任意节点值都不同

递归

根据二叉搜索树的性质,插入节点的话,若该值大于当前节点值,这肯定要插到当前节点的右子树,否则插入到左子树。递归下去,直到当前节点为空,则插入该值。

/**
 * 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:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if(root==nullptr){
            root = new TreeNode(val);
            return root;
        }
        if(val > root->val)
                root->right= insertIntoBST(root->right,val);
        else
                root->left = insertIntoBST(root->left,val);
        return root;
    }
};
  • 时间复杂度O(n) ,n为节点数目,最坏情况下,该树为链状。
  • 空间复杂度O(n) 递归的栈开销。

模拟(算是迭代吧)

算法和上一个解法一样

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if (root == nullptr) {
            return new TreeNode(val);
        }
        TreeNode* pos = root;
        while (pos != nullptr) {
            if (val < pos->val) {
                if (pos->left == nullptr) {
                    pos->left = new TreeNode(val);
                    break;
                } else {
                    pos = pos->left;
                }
            } else {
                if (pos->right == nullptr) {
                    pos->right = new TreeNode(val);
                    break;
                } else {
                    pos = pos->right;
                }
            }
        }
        return root;
    }
};

  • 时间复杂度O(n)
    root = new TreeNode(val);
    return root;
    }
    if(val > root->val)
    root->right= insertIntoBST(root->right,val);
    else
    root->left = insertIntoBST(root->left,val);
    return root;
    }
    };

- 时间复杂度O(n)  ,n为节点数目,最坏情况下,该树为链状。
- 空间复杂度O(n)  递归的栈开销。

**模拟(算是迭代吧)**

算法和上一个解法一样

~~~cpp
class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if (root == nullptr) {
            return new TreeNode(val);
        }
        TreeNode* pos = root;
        while (pos != nullptr) {
            if (val < pos->val) {
                if (pos->left == nullptr) {
                    pos->left = new TreeNode(val);
                    break;
                } else {
                    pos = pos->left;
                }
            } else {
                if (pos->right == nullptr) {
                    pos->right = new TreeNode(val);
                    break;
                } else {
                    pos = pos->right;
                }
            }
        }
        return root;
    }
};

  • 时间复杂度O(n)
  • 空间复杂度O(1)

9月水水水!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值