Leetcode 111-120

LeetCode 111. 二叉树的最小深度

分析

递归分析左右子树.
根据定义, 如果u是叶子结点, 那么深度为1.
如果不是叶子节点, 分成3种情况
1.左子树a, 右子树b 不空, 返回min(f(a), f(b)) + 1
2.a不空, b空, 返回f(a) + 1
3.a空, b不空 返回f(b) + 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:
    int minDepth(TreeNode* root) {
        if (!root) return 0;
        if (!root->left && !root->right) return 1; // 如果是叶子节点 返回1
        if (root->left && root->right) return min(minDepth(root->left), minDepth(root->right)) + 1;
        if (root->left) return minDepth(root->left) + 1;
        return minDepth(root->right) + 1;
    }
};

LeetCode 112. 路径总和

分析

自上而下递归, 然后判断叶子结点的sum是否==0
在这里插入图片描述

代码

/**
 * 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 hasPathSum(TreeNode* root, int sum) {
        if (!root) return false;
        sum -= root->val;
        if (!root->left && !root->right) return !sum;
        return root->left && hasPathSum(root->left, sum) || root->right && hasPathSum(root->right, sum);

    }
};

LeetCode 113. 路径总和 II

分析

新建一个dfs函数去递归, 不要在原函数中递归
还要新建全局变量res, path

代码

/**
 * 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<vector<int>> res;
    vector<int> path;
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        if (root) dfs(root, sum);
        return res;
    }
    void dfs(TreeNode* root, int sum){
        path.push_back(root->val);
        sum -= root->val;
        if (!root->left && !root->right){
            if (!sum) res.push_back(path);
        }else{
            if (root->left) dfs(root->left, sum);
            if (root->right) dfs(root->right, sum);
        }
        path.pop_back();
    }
};

LeetCode 114. 二叉树展开为链表

分析

在这里插入图片描述
在这里插入图片描述

代码

/**
 * 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:
    void flatten(TreeNode* root) {
        while (root){
            auto p = root->left;
            if (p){
                while (p->right) p = p->right;
                p->right = root->right;
                root->right = root->left;
                root->left = NULL;
            }
            root = root->right;
        }   
    }
};

LeetCode 115. 不同的子序列

分析

闫氏dp分析法.
f[i][j] 表示s[1~i]所有前i个字符和t前j个字符匹配的子序列
注意 右边是无条件可以选择的情况, 所以f[i][j] = f[i - 1][j]
在这里插入图片描述
中间结果会爆int, 用longlong存储

代码

class Solution {
public:
    int numDistinct(string s, string t) {
        typedef unsigned long long ULL;
        int n = s.size(), m = t.size(); 
        s = ' ' + s, t = ' ' + t;
        vector<vector<ULL>> f(n + 1, vector<ULL>(m + 1));
        for (int i = 0; i <= n; i ++ ) f[i][0] = 1;
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= m; j ++ ) {
                f[i][j] = f[i - 1][j];
                if (s[i] == t[j]) f[i][j] += f[i - 1][j - 1];
            }

        return f[n][m];
    }
};

116. 填充每个节点的下一个右侧节点指针

分析

可以发现指针, 从前指向后, 第1层就是全部是第一层的节点, 第2层全部都是第2层的节点…
所以按照宽搜的思路来做就可以了, 宽搜的过程中赋下Next指针就可以了
宽搜本来是需要队列的, 但是这题中有next指针, 所以宽搜的时候next指针也是可以省掉的
宽搜的时候怎么去初始化next的值呢, 分情况讨论
比如2这个点
左儿子的next = 右儿子, 但是右儿子的next怎么处理呢, 应该指向下一个点的左儿子, 2->right ->next = 2->next->left
当然还需特判下有没有下一个点, 每层最后一个点没有下一个点
在这里插入图片描述

code

右儿子处理的时候, 需要保证当前父亲节点右边还有节点

在这里插入图片描述

因为每个节点next初始化为NULL, 所以如果没有, 那就默认即可, 不用建立

简单来说, 就是在当前层, 需要对下一层的next指针进行赋值, 但是需要下一层得先存在, 所以刚开始得while(下一层存在root->left)

/*
// 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) {
        if (!root) return root;
        auto source = root; // 存一下根, 返回用
        // 当有左儿子时, 说明有下一层
        while (root->left){
            // 使用next遍历这一层的每个节点p, 来处理当前层的链接关系
            for (auto p = root; p; p = p->next){
                p->left->next = p->right; // 左儿子指向 右儿子
                if (p->next) p->right->next = p->next->left; // 右儿子指向的时候, 需要先保证p的右边还有东西
            }
            root = root->left;// 走向下一层
        }
        return source;
    }
};

117. 填充每个节点的下一个右侧节点指针 II

分析

扩展题, 如果按照上一题的做法, 让每个点的左儿子指向右儿子, 然后右儿子指向next点的左儿子,
然后这题, 比如下图, 7指向谁呢, 不知道诶, 因为对于4而言, 4可能没有右儿子, 4的next可能都没有儿子
所以不能按照上一题的思路做

在这里插入图片描述

需要在遍历前一层的时候, 将后一层的next建立出来, 遍历的时候, 由于不知道每个点是否存在左右儿子, 自己去维护下一层的单链表
需要记录下一层的头节点
假如新点的时候, 是让当前链表的末尾的next指向当前点, 因此还需要记录一个信息尾节点
每次迭代的时候, 只看两个变量, 因此也是O(1)
在这里插入图片描述
简单来说, 就是循环当前层, 然后对下一层建立单链表, 因为不知道下一层存不存在, 所以建立单链表的时候得判断 左儿子, 右儿子的情况

code

/*
// 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) {
        if (!root) return root;
        auto cur = root;
        while (cur){
            auto head = new Node(-1);
            auto tail = head;
            for (auto p = cur; p; p = p->next){
            	// 当前层是p, 建立下一层的next指向
                if (p->left) tail = tail->next = p->left;
                if (p->right) tail = tail->next = p->right;
            }
            cur = head->next; // 跳到下一层
        }
        return root;
    }
};

118. 杨辉三角

分析

递归下就可以了,
注意i从0开始, 所以每一层数组长度为i + 1
然后0, i位置已经定了
所以每一层从[1, i)循环

code

class Solution {
public:
    vector<vector<int>> generate(int n) {
        vector<vector<int>> res;
        for (int i = 0; i < n; i ++ ){
            vector<int> level(i + 1);
            level[0] = level[i] = 1;
            for (int j = 1; j < i; j ++ )
                level[j] = res[i - 1][j - 1] + res[i - 1][j];
            res.push_back(level);
        }
        return res;
    }
};

LeetCode 119. 杨辉三角 II

分析

可以发现f[i][j] = f[i - 1][j - 1] + f[i - 1][j]
所以可以用一个滚动数组

在这里插入图片描述

所以第n行应该存到 n % 2行, n % 2 = n & 1

code

先不用滚动数组写

class Solution {
public:
    vector<int> getRow(int n) {
        vector<vector<int>> f(n + 1, vector<int>(n + 1));
        for (int i = 0; i <= n; i ++ ){
            f[i][0] = f[i][i] = 1;
            for (int j = 1; j < i; j ++ )
                f[i][j] = f[i - 1][j - 1] + f[i - 1][j];
        }
        return f[n];
    }
};

&1转化为滚动数组

class Solution {
public:
    vector<int> getRow(int n) {
        vector<vector<int>> f(2, vector<int>(n + 1));
        for (int i = 0; i <= n; i ++ ){
            f[i & 1][0] = f[i & 1][i] = 1;
            for (int j = 1; j < i; j ++ )
                f[i & 1][j] = f[i - 1 & 1][j - 1] + f[i - 1 & 1][j];
        }
        return f[n & 1];
    }
};

120. 三角形最小路径和

分析

自下向上考虑, 没有边界问题

联动题

AcWing寒假每日一题 数字三角形

code

注意从倒数第2行开始算; 如果从倒数第1行 (n - 1), 那么递推式i + 1会越界
并且注意第i行(i从0开始)有 i + 1个数,比如第0行, 1个数, 第1行, 2个数, 第2行, 3个数, 因此j循环范围[0, i]

class Solution {
public:
    int minimumTotal(vector<vector<int>>& t) {
        int n = t.size();
        for (int i = n - 2; i >= 0; i -- )
            for (int j = 0; j <= i; j ++ ){
                t[i][j] = t[i][j] + min(t[i + 1][j], t[i + 1][j + 1]);
            }
        return t[0][0];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值