LeetCode刷题记录

文章目录

    • 1. LeetCode 113 - 路径总和 II
    • 2. LeetCode 236 - 二叉树的最近公共祖先
    • 3. LeetCode 289 - 生命游戏
    • 4. LeetCode 91 - 二叉树的中序遍历

1. LeetCode 113 - 路径总和 II

1、 二叉树的先序遍历可以理解为深度搜索,首先搜索到最左叶子节点并可以得到路径所有节点的值,再在遍历过程中会对树整体从左到右每一个叶子节点的路径(根节点到叶子节点的所有节点)进行搜索(叶子节点不一定在同一层),相当于深度搜索;
2、 vector实现stack,push_back()相当于压栈,pop_back()相当于弹出栈顶元素,这样一来既可以实现栈的功能(得到搜索路径,且首元素为根节点,即栈底,符合该题输出要求),也可以反向输出栈的元素(从底到顶),想了一下好像双端队列也可以实现这个功能。

2. LeetCode 236 - 二叉树的最近公共祖先

1、核心思路就是当两节点有公共的离根节点最远的祖先时,在这两个节点的搜索路径上(分别表示为pathP和pathQ),这个祖先之前的搜索路径是相同的,也就是路径pathP和pathQ最前面是完全一样的,当出现第一个不一样的路径节点时,前一个节点就是最近公共祖先(也即离根节点最远的公共祖先);
2、那么解题思路就和1差不多了,先通过二叉树的遍历算法求取两个节点的路径,然后比较路径,路径可以用vector来存储,便于比较;
3、写的过程中碰到一个BUG,如果没有用result数组来就地存下寻找到的路径的话,会因为函数递归的问题,上层递归函数由于存在最后一行代码path.pop_back()把原本保存好的地址给弹出,导致程序只会记录根节点。

/**
 * 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 {
    // 二叉树node中搜索key的路径,并保存至path中
    // 函数需要一个参数result来接收当时的结果,否则在递归调用的过程中虽然当时path是路径结果,但是其上层调用会pop_back()掉一些元素
    void searchPath(TreeNode* node, TreeNode* key, vector<TreeNode*> &path, vector<TreeNode*> &result, int &flag)
    {
        // 找到节点或者到了叶子节点就返回
        if(!node || flag){
            return;
        }
        // 先序遍历搜索路径
        // 路径压栈,搜索根节点到节点key的路径
        path.push_back(node);
        if(node == key){
            flag = 1;
            result = path;
            return;
        }
        searchPath(node->left, key, path, result, flag);
        searchPath(node->right, key, path, result, flag);
        path.pop_back();
    }
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // 存储两个节点的搜索路径
        vector<TreeNode*> pathP, resultP;
        vector<TreeNode*> pathQ, resultQ;
        int finP = 0, finQ = 0;
        searchPath(root, p, pathP, resultP, finP);
        searchPath(root, q, pathQ, resultQ, finQ);
        TreeNode* publicNode = NULL;
        for(int i = 0, n=min(resultQ.size(), resultP.size()); i<n; i++){
            if(resultP[i]==resultQ[i])
                publicNode = resultQ[i];
            else
                break;
        }
        return publicNode;
    }
};

3. LeetCode 289 - 生命游戏

1、题目有点长,其实意思还是挺清晰,总结来看就是对一个点求8邻域内的值为1元素总和(1为活细胞),然后根据当前元素判断是要将该元素置1还是置0;
2、常规解法很容易想,就相当于图像的卷积,每个邻域求出结果然后开一个新的数组存储结果(否则在原数组更新会有问题,因为要求同时更新),最后再把值赋给原数组;
3、主要记录一下这个8邻域的查询思想吧,因为要判断数组下标是否越界,一开始是想只用两个嵌套for循环来循环行和列并用if来判断索引是否越界,后来写着写着发现情况好复杂,要判断row>=0/row=0/col这么多情况而且它们有一定的组合,这样写代码也太复杂(全是if/else而且嵌套很多层),后来看了一下题解才发现之前用过的方向数组可以解决这个问题,只不过多嵌套两层循环(这里是8邻域,之前写的题都是4邻域,所以可以用两个交错的dx/dy方向数组来一层循环实现),然后可以在根据方向数组得到8邻域元素的索引后再用一个单一的if条件语句来判断是否数组索引越界,这样就简化了代码很多!而且if判断中需要用到!(i==1&&j==1)这个条件,目的是为了防止读取到的是中心元素(也就是需要修改的元素)。
4、题目提示可以采用原地算法(直接原数组操作)来解,想了一会儿想不出,看到题解好像是说可以用位操作来解,还是我太菜了o(╥﹏╥)o

class Solution {
public:
    void gameOfLife(vector<vector<int>>& board) {
        vector<vector<int>> res(board);
        int neighbors[3] = {1, 0, -1};
        int rows = board.size(), cols = board[0].size();

        for(int row = 0; row<rows; row++){
            for(int col = 0; col<cols; col++){
                // 对每个细胞进行查询,相当于卷积
                int count = 0;
                for(int i = 0; i<3; i++){
                    for(int j=0; j<3; j++){
                        int dr = row + neighbors[i];
                        int dc = col + neighbors[j];
                        // 防止数组越界
                        if(dr>=0 && dr<rows && dc>=0 && dc<cols && !(i==1&&j==1) && board[dr][dc]==1)
                            count++;
                    }
                }
                // 根据规则判别
                if(board[row][col]==1){
                    if(count<2) res[row][col]=0;
                    else if(count==2 || count==3) res[row][col]=1;
                    else res[row][col]=0;
                }
                else{
                    if(3==count) res[row][col]=1;
                    else res[row][col]=0;
                }
            }
        }
        board = res;
    }
};

4. LeetCode 91 - 二叉树的中序遍历

实现了递归法和非递归法,非递归法利用了栈,主要是理清中序遍历的逻辑顺序。

/**
 * 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 inorderTraversal(TreeNode* root) {
        vector res;
        inorder(res, root);
        return res;
    }

    void inorder(vector &res, TreeNode* node){
        if(node==nullptr) return;
        inorder(res, node->left);
        res.push_back(node->val);
        inorder(res, node->right);
    }*/

    // 非递归解法
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> sinorder;
        TreeNode* p=root;

        // 当栈中还有元素或者p不为空时,继续循环
        while(p!=nullptr || !sinorder.empty()){
            // p为空的时候就要退出到上一个节点并输出
            // 然后把右子节点压入路径
            if(p==nullptr){
                // 按照栈的顺序输出
                p=sinorder.top();
                sinorder.pop();
                res.push_back(p->val);
                // 输出完后压入右子节点
                p=p->right;
            }
            // p不为空时就继续向左子节点深入 
            else {
                sinorder.push(p);
                p=p->left;
            }
        }
        return res;
    }
};

你可能感兴趣的:(C/C++,LeetCode)