leetcode 刷题日志 2018-3-28

 

树:

404. 左叶子之和

求所有左叶子结点之和
1. 递归法
分析:递归法遍历结点,找左叶子结点
        空指针判断
        有左子节点?是叶子结点?是的话更新value的值

int sumOfLeftLeaves(TreeNode* root) {
        if(!root) return 0; // NULL 
        int value = 0;
        if(root->left){ //左子节点
                if(!root->left->left && !root->left->right) //是不是叶子结点?
                        value = root->left->val ;
        }
        return value + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);
}


2.非递归法遍历寻找所有左叶子结点 int sumOfLeftLeaves(TreeNode* root) { if(!root) return 0; //注意一定要处理空指针 int res = 0; queue<TreeNode*> q; q.push(root); while(!q.empty()){ root = q.front(); q.pop(); if(root->left){ //左子节点 q.push(root->left); if(!root->left->left && !root->left->right){ //是否为叶子结点 res += root->left->val; } } if(root->right){ q.push(root->right); } } return res; }

 

671. Second Minimum Node In a Binary Tree

题意:求二叉树第二小值,没有返回-1
分析:用set存所有节点,最终容量大于2,代表存在第二小值,输出*(++set.begin())
```
int findSecondMinimumValue(TreeNode* root) {
            if(!root) return -1;
            int res = -1;
            queue<TreeNode* > q;
            q.push(root);
            set<int> s;
            while (!q.empty())
            {
                    root = q.front();
                    s.insert(root->val);
                    q.pop();
                    if (root->left) {
                            q.push(root->left);
                    }
                    if (root->right) {
                            q.push(root->right);
                    }
            }
            if(s.size() < 2) res = -1;
            else res = *(++s.begin());
            return res;
}

 102. 二叉树的层次遍历

二叉树层次遍历且每层输出
算法记忆:一层一循环
```
vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int> > res;
        vector<int> tmp;
        if(!root) return res;
        queue<TreeNode*> q;
        q.push(root);
        int currentLevelTotalNum = 0;
        while(!q.empty())
        {
            tmp.clear();
            currentLevelTotalNum = q.size();
            while(currentLevelTotalNum--){  //一层一循环
                root = q.front();
                tmp.push_back(root->val);
                q.pop();
                if(root->left){
                    q.push(root->left);
                }
                if(root->right){
                    q.push(root->right);
                }
            }
            res.push_back(tmp);
        }
        return res;
    }
```

 

107. 二叉树的层次遍历 II

分析:在正序层析遍历基础上,用栈临时存一下

vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int> > res;
        vector<int> tmp;
        stack<vector<int> >tmps;
        if(!root) return res;
        queue<TreeNode*> q;
        q.push(root);
        int currentLevelTotalNum = 0;
        while(!q.empty())
        {
            tmp.clear();
            currentLevelTotalNum = q.size();
            while(currentLevelTotalNum--){  //一层一循环
                root = q.front();
                tmp.push_back(root->val);
                q.pop();
                if(root->left){
                    q.push(root->left);
                }
                if(root->right){
                    q.push(root->right);
                }
            }
            tmps.push(tmp);
        }
        while(!tmps.empty()){
            res.push_back(tmps.top());
            tmps.pop();
        }
        return res;
    }

 637. 二叉树的层平均值

题意:求二叉树每层平均值(double)所组成的数组
分析:每层求和取平均值
```
vector<double> averageOfLevels(TreeNode* root) {
        vector<double> res;
        if(!root) return res;
        queue<TreeNode* > q;
        q.push(root);
        int currentLevelTotalNum = 0, n = 0;
        double tmpd;
        while(!q.empty()){
            currentLevelTotalNum = q.size();
            n = currentLevelTotalNum;
            tmpd = 0;
            while(currentLevelTotalNum--){ //此层所有节点
                root = q.front();
                tmpd +=root->val;
                q.pop();
                if(root->left){
                    q.push(root->left);
                }
                if(root->right)
                {
                    q.push(root->right);
                }
            }
            tmpd /= n;
            res.push_back(tmpd);
        }
        return res;
    }
```

 101. 对称二叉树

关键点在于递归比较。

题意:给定一个二叉树,检查它是否是它自己的镜像(即,围绕它的中心对称)。
分析:一个结点左子节点l,与右子节点r比较,递归的判断整棵树,l的左与r的右 且l的右跟r的左比较
抽取出递归模型如下
```
bool is(TreeNode* root1, TreeNode* root2){
        if(!root1 && !root2) return true;
        if(!root1) return false;
        if(!root2) return false;
        if(root1->val != root2->val){
            return false;
        }
        return is(root1->left,root2->right) && is(root1->right,root2->left);
    }
    bool isSymmetric(TreeNode* root) {
        if(!root) return true;
        return is(root->left,root->right);
    }
```

 111. 二叉树的最小深度

题意:二叉树最小深度(从根节点到叶子结点的结点个数,包含两端)
分析:递归,
终结条件是 1. root ==NULL 0  2. 叶子结点 1
分别计算左子树、右子树的长度
取最小值,因为加上本结点所以最终返回值+1
```
int minDepth(TreeNode* root) {
        if(!root) return 0;
        if(!root->left && !root->right)
            return 1;
        int left,right;
        if(root->left) left = minDepth(root->left);
        else left = INT_MAX;
        if(root->right) right = minDepth(root->right);
        else right = INT_MAX;
        return min(left,right) + 1;
    }
```

 104. 二叉树的最大深度

题意:最大二叉树深度
分析:递归法
1.终结条件:
        1. NULL 0
        2. 叶子结点 1
2. 分别计算左右子树长度
3. 返回max(left,right)+1 加1是因为加上本结点
```
int maxDepth(TreeNode* root) {
        if(!root) return 0;
        if(!root->left && !root->right) return 1;
        int left, right;
        if(root->left) left = maxDepth(root->left);
        else left = INT_MIN;
        if(root->right) right = maxDepth(root->right);
        else right = INT_MIN;
        return max(left,right) + 1;
    }
```

 

110. 平衡二叉树

题意:判断是否为平衡二叉树
分析:
本题是递归数深度遍历的一种应用。按照题目的意思,对于一个节点分别算出每个节点的左、右子树的深度,如果左、右子树深度差大于1,则可以该树非平衡。
那么递归每一个节点,一旦发现某一节点非平衡,就返回false,如果每一节点都平衡,则返回true: ```
//获取树的深度 int getDepth(TreeNode* root){ if(!root) return 0; return max(getDepth(root->left),getDepth(root->right)) + 1; } //递归判断每个结点的子树是否满足长度只差不大于1 bool isBalanced(TreeNode* root) { if(!root) return true; if(abs(getDepth(root->left) - getDepth(root->right)) > 1){ return false; } return isBalanced(root->left) && isBalanced(root->right); } ```

 144. 二叉树的前序遍历 +1 2

题目:二叉树,前序遍历,迭代法

分析:DFS,用到栈,一直沿着左指针将沿路节点压入栈内,当到尽头,弹出top结点,将其右子树压入,右子树同样是先沿着左指针压到尽头后,向右展

记忆:深搜栈右展

```
vector<int> res;
    vector<int> preorderTraversal(TreeNode* root) {
        //递归
        if(root){
            res.push_back(root->val);
            preorderTraversal(root->left);
            preorderTraversal(root->right);
        }   return res;
}

vector<int> preorderTraversal(TreeNode* root) {
            //迭代
            vector<int> res;
            if(!root) return res;
            stack<TreeNode*> s;
            while (!s.empty() || root != NULL)
            {
                    if (root) { //至最左
                            res.push_back(root->val);
                            s.push(root);
                            root = root->left;
                    } else { //左到尽头,往右走
                            root = s.top();
                            s.pop();
                            root = root->right;
                    }
            }
            return res;
    }



```

 94. 中序遍历二叉树 1+2

题意: 二叉树中序遍历,迭代法

分析: DFS,利用栈,沿着左指针将一直到最左端的沿路所有节点依次压入栈中,每到到最左端向右展一下

记忆:深搜栈右展

```
vector<int> inorderTraversal(TreeNode* root) {
            stack< TreeNode* > s;
            TreeNode * p = root;
            vector<int> tmp;
            while(!s.empty() || p!=NULL){
                    while(p){ //到最左端
                            s.push(p);
                            p=p->left;
                    }
                    if(!s.empty()){  //右展一次
                            p=s.top();
                            tmp.push_back(p->val);
                            s.pop();
                            p=p->right;
                    }
            }
            return tmp;
    }


```

 145. 二叉树的后序遍历 1 2 + 迭代法

分析:同样用到栈

记忆:+21入栈,处理两情况

//递归法
```
vector<int> res;
    vector<int> postorderTraversal(TreeNode* root) {
        if(root){
            postorderTraversal(root->left);
            postorderTraversal(root->right);
            res.push_back(root->val);
        }
        return res;
    }
```
//迭代法
```
vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        if(!root) return res;
        stack<TreeNode* > s;
        TreeNode *cur = root, *pre = NULL;
        s.push(cur);
        // 栈中的顺序是后序遍历的反序,先压入根,再压入右结点,左结点
        while (!s.empty())
        {
            cur = s.top();
            if((!cur->left && !cur->right) || (pre && (cur->left == pre || cur->right == pre))) //叶子结点直接处理 || 刚刚处理完左右结点
            {
                res.push_back(cur->val);
                pre = cur;
                s.pop();
            }
            else{
                if(cur->right){
                    s.push(cur->right);
                }
                if (cur->left)
                    s.push(cur->left);
            }
        }
        return res;
    }
```

 617. 合并二叉树

/*
题意:合并两棵二叉树,对应结点相加,否则补上
分析:递归实现
                根节点都为空,return NULL
                根节点都不为空,求和
                根节点有一个空,补上
                进一步分析左右子树
前三步就是抽取出来的子过程
*/
```
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if(!t1 && !t2) return NULL;
        if (t1 && t2) {
            t1->val += t2->val;
            t2->val = t1->val;
        }
        else if (t1) {
            t2 = new TreeNode(t1->val);
        }
        else if (t2) {
            t1 = new TreeNode(t2->val);
        }
        t1->left = mergeTrees(t1->left,t2->left);
        t1->right = mergeTrees(t1->right,t2->right);
        return t1;
    }
```

 114. 二叉树转换链表

题意:二叉树转换链表;将所有结点编程右指针连接
分析:将前序遍历序列,顺序串联

```
//迭代版,前序遍历
    vector<TreeNode*> preOrder2(TreeNode* root) {
        vector<TreeNode*> res;
        if(!root) return res;
        stack<TreeNode*> s;
        TreeNode* p = root;
        while(!s.empty() || p)
        {
            while(p){   //一直往左
                res.push_back(p);
                s.push(p);
                p = p->left;
            }
            if(!s.empty()){ //右展
                p = s.top();
                s.pop();
                p = p->right;
            }
        }
        return res;
    }
    // 注意只需保留头指针,指针传递,传递方保留着头指针,他顺着访问就是了
    void flatten(TreeNode* root) {
        if(!root) return ;
        //前序遍历结果
        vector<TreeNode*> preOrderV = preOrder2(root);
        int len = preOrderV.size();
        root->left = NULL;
        root->right = NULL;
        //链表形成
        for(int i=0;i<len;i++)
        {
            root->right = preOrderV[i];
            root = preOrderV[i];
            root->left = NULL;
            root->right =NULL;
        }
    }
```

 112. 路径总和

/*
题意:路径总和,给一棵二叉树和一个整数sum,问是否存在从根节点到叶节点的路径,求和等于sum
分析:递归,和递减
*/
```
bool hasPathSum(TreeNode* root, int sum) {
        if(!root) return false;
        if(root->val == sum){ //恰好有叶节点满足
            if(!root->left && !root->right){
                return true;
            }
        }
        return hasPathSum(root->left,sum-root->val) || hasPathSum(root->right,sum-root->val);
    }
```

 113. 路径总和 II

题意:找出一棵二叉树里,路径(根结点到叶结点)上结点之和等于sum的所有路径

分析:经典递归回溯问题,搜集路径上所有节点时,注意遇到结点push,用完节点pop

经典递归回溯
```
vector<vector<int> >result;
    vector<int> path;
    // 经典递归回溯问题
    void findPath(TreeNode* root, int sum) {
        if(!root) return ;
        if(root->val == sum && !root->left && !root->right ) { //find a path equal sum && It's a leaf node 
            path.push_back(root->val);
            result.push_back(path); // find a path
            path.pop_back(); //!!
            return ;
        }
        path.push_back(root->val); // 经过节点压入
        findPath(root->left, sum - root->val);
        findPath(root->right, sum - root->val);
        path.pop_back(); // 对与此节点的左右子树都已经处理完,弹出此节点 !
    }
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> res;
        if(!root) return res;
        findPath(root, sum);
        return result;
    }
```

 257. 二叉树的所有路径

/*
题意:输出二叉树所有路径
分析:经典递归回溯法
*/
```
vector<vector<int> >allPath; //所有路径
    vector<int> aPath; //单条路径
    // 经典递归回溯法求二叉树所有路径
    void findPath(TreeNode* root) {
        if(!root) return ;
        if(!root->left && !root->right) { //leaf node
            aPath.push_back(root->val);
            allPath.push_back(aPath);   // a path
            aPath.pop_back();
            return ;
        }
        aPath.push_back(root->val);
        findPath(root->left);
        findPath(root->right);
        aPath.pop_back();
    }
    
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> res;
        if(!root) return res;
        findPath(root);
        int len = allPath.size();
        string tmpS = "";
        for (int i=0; i<len; i++) {
            tmpS = std::to_string(allPath[i][0]);
            for (int j=1; j<allPath[i].size(); j++) {   //形成路径字符串
                tmpS += ("->" + std::to_string(allPath[i][j]));
            }
            res.push_back(tmpS);
        }
        return res;
    }
```

 

posted @ 2018-03-30 00:42  kimsimple  阅读(189)  评论(0编辑  收藏  举报