剑指Offer II --- 2021/9/5

目录

  • 剑指 Offer II 104. 排列的数目
  • 剑指 Offer II 105. 岛屿的最大面积
  • 剑指 Offer II 041. 滑动窗口的平均值
  • 剑指 Offer II 106. 二分图
  • 剑指 Offer II 043. 往完全二叉树添加节点
  • 剑指 Offer II 107. 矩阵中的距离
  • 剑指 Offer II 044. 二叉树每层的最大值
  • 剑指 Offer II 045. 二叉树最底层最左边的值
  • 剑指 Offer II 046. 二叉树的右侧视图
  • 剑指 Offer II 047. 二叉树剪枝
  • 剑指 Offer II 109. 开密码锁

剑指 Offer II 104. 排列的数目

剑指Offer II --- 2021/9/5_第1张图片
分析:
  动态规划:设dp[i]表示总和为i的组合的个数,最终需要返回dp[target];初始条件:dp[0] = 1;转移方程:dp[i]等于所有dp[i - x]之和,x是nums中的元素。
代码:

class Solution {
     
public:
    int combinationSum4(vector<int>& nums, int target) {
     
        vector<long long> dp(target + 1);
        dp[0] = 1;
        for(int i = 1; i <= target; i++) {
     
            for(int& x : nums) {
     
                if(x <= i && dp[i] + dp[i - x] <= INT_MAX) {
     
                    dp[i] += dp[i - x];
                }
            }
        }
        return dp[target];
    }
};

剑指 Offer II 105. 岛屿的最大面积

岛屿最大面积

剑指 Offer II 041. 滑动窗口的平均值

剑指Offer II --- 2021/9/5_第2张图片
分析:
  双端队列deque:元素入队后如果队列长度大于滑动窗口长度,则队头元素出队。
代码:

class MovingAverage {
     
public:
    /** Initialize your data structure here. */
    long long sum = 0;
    int max_cnt = 0;
    deque<int> que;
    MovingAverage(int size) {
     
        max_cnt = size;
    }
    
    double next(int val) {
     
        que.push_back(val);
        sum += val;
        if(que.size() > max_cnt) {
     
            sum -= que.front();
            que.pop_front();
        }
        // cout << sum << " " << que.size() << endl;
        double x = (double)sum / que.size();
        return x;
    }
};

/**
 * Your MovingAverage object will be instantiated and called as such:
 * MovingAverage* obj = new MovingAverage(size);
 * double param_1 = obj->next(val);
 */

剑指 Offer II 106. 二分图

剑指Offer II --- 2021/9/5_第3张图片
分析:
  并查集:对每一个节点的节点数组,如果存在一个跟该节点在一个集合的节点,说明一条边的两个节点在同一个集合里面,不是二分图,返回false;否则将节点数组里面的所有节点合并到一个集合里面。
代码:

class Solution {
     
private:
    vector<int> par;
    void init(int n) {
     
        par.resize(n);
        for(int i = 0; i < n; i++) {
     
            par[i] = i;
        }
    }
    
    int get_root(int x) {
     
        if(par[x] != x) {
     
            par[x] = get_root(par[x]);
        }
        return par[x];
    }
    
    void merge(int x, int y) {
     
        par[get_root(x)] = get_root(y);
    }
    
    bool check(int x, int y) {
     
        return get_root(x) == get_root(y);
    }
    
public:
    bool isBipartite(vector<vector<int>>& graph) {
     
        int n = graph.size();
        init(n);
        for(int i = 0; i < n; i++) {
     
            for(int& x : graph[i]) {
     
                if(check(i, x)) {
     
                    return false;
                }
            }
            for(int j = 1; j < graph[i].size(); j++) {
     
                merge(graph[i][0], graph[i][j]);
            }
        }
        return true;
    }
};

剑指 Offer II 043. 往完全二叉树添加节点

剑指Offer II --- 2021/9/5_第4张图片
分析:
  二叉树的结点序号如果从0开始,则序号为i的左右子树结点(如果有的话)序号分别为2i+1和2i+2。
代码:

/**
 * 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 CBTInserter {
     
public:
    vector<TreeNode*> nodes;
    CBTInserter(TreeNode* root) {
     
        if(root == NULL) {
     
            return;
        }
        //建树
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
     
            TreeNode* fr = que.front();
            nodes.push_back(fr);
            que.pop();
            if(fr->left) {
     
                que.push(fr->left);
            }
            if(fr->right) {
     
                que.push(fr->right);
            }
        }
    }
    
    int insert(int val) {
     
        TreeNode* x = new TreeNode(val);
        nodes.push_back(x);
        int ind = nodes.size() - 1;
        int fa = 0;
        if(ind & 1) {
     
            //左子树
            fa = (ind - 1) / 2;
            nodes[fa]->left = x;
        }else {
     
            //右子树
            fa = (ind - 2) / 2;
            nodes[fa]->right = x;
        }
        return nodes[fa]->val;
    }
    
    TreeNode* get_root() {
     
        return nodes.size() == 0 ? NULL : nodes[0];
    }
};

/**
 * Your CBTInserter object will be instantiated and called as such:
 * CBTInserter* obj = new CBTInserter(root);
 * int param_1 = obj->insert(val);
 * TreeNode* param_2 = obj->get_root();
 */

剑指 Offer II 107. 矩阵中的距离

01矩阵

剑指 Offer II 044. 二叉树每层的最大值

剑指Offer II --- 2021/9/5_第5张图片
分析:
  层序遍历。
代码:

/**
 * 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> largestValues(TreeNode* root) {
     
        vector<int> res;
        if(root == NULL) {
     
            return res;
        }
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
     
            int n = que.size();
            int re = INT_MIN;
            for(int i = 0; i < n; i++) {
     
                TreeNode* fr = que.front();
                que.pop();
                re = max(re, fr->val);
                if(fr->left) {
     
                    que.push(fr->left);
                }
                if(fr->right) {
     
                    que.push(fr->right);
                }
            }
            res.push_back(re);
        }
        return res;
    }
};

剑指 Offer II 045. 二叉树最底层最左边的值

找树左下角的值

剑指 Offer II 046. 二叉树的右侧视图

二叉树的右视图

剑指 Offer II 047. 二叉树剪枝

剑指Offer II --- 2021/9/5_第6张图片
分析:
  递归。
代码:

/**
 * 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* pruneTree(TreeNode* root) {
     
        if(root == NULL) {
     
            return NULL;
        }
        TreeNode* lt = pruneTree(root->left);
        TreeNode* rt = pruneTree(root->right);
        if(root->val == 0 && lt == NULL && rt == NULL) {
     
            return NULL;
        }
        root->left = lt;
        root->right = rt;
        return root;
    }
};

剑指 Offer II 109. 开密码锁

剑指Offer II --- 2021/9/5_第7张图片
分析:
  求从一个状态变化到另一个状态的最短步骤,往往就会想到BFS,此题与2017蓝桥杯省赛:青蛙跳杯子(BFS求最短路径长度)类似。
代码:

class Solution {
     
public:
    int openLock(vector<string>& deadends, string target) {
     
        //bfs
        queue<pair<string, int>> que;
        unordered_set<string> dead(deadends.begin(), deadends.end());
        unordered_set<string> st;
        if(dead.count("0000")) {
     
            return -1;
        }
        st.insert("0000");
        que.push(make_pair("0000", 0));
        int dirs[8][2] = {
     {
     0, 1}, {
     0, -1}, {
     1, 1}, {
     1, -1}, {
     2, 1}, {
     2, -1}, {
     3, 1}, {
     3, -1}};
        while(!que.empty()) {
     
            auto p = que.front();
            string x = p.first;
            int step = p.second;
            que.pop();
            if(x == target) {
     
                return step;
            }
            for(int k = 0; k < 8; k++) {
     
                string t = x;
                int i = dirs[k][0];
                if(t[i] == '0' && dirs[k][1] == -1) {
     
                    t[i] = '9';
                }else if(t[i] == '9' && dirs[k][1] == 1) {
     
                    t[i] = '0';
                }else {
     
                    t[i] += dirs[k][1];
                }
                if(dead.count(t) == 0 && st.count(t) == 0) {
     
                    que.push(make_pair(t, step + 1));
                    st.insert(t);
                }
            }
        }
        return -1;
    }
};

总结一下层序遍历的题目:

  1. 二叉树的锯齿形层序遍历
  2. 二叉树的右视图
  3. 填充每个节点的下一个右侧节点指针
  4. 二叉树的层序遍历
  5. 剑指 Offer 32 - II. 从上到下打印二叉树 II
  6. 剑指 Offer 55 - I. 二叉树的深度
  7. 剑指 Offer 32 - III. 从上到下打印二叉树 III
  8. 找树左下角的值
  9. 二叉树的层平均值

你可能感兴趣的:(LeetCode,bfs,二叉树,并查集,动态规划,leetcode)