Leetcode 每日一题和每日一题的下一题刷题笔记 25/30

220 阅读3分钟

Leetcode 每日一题和每日一题的下一题刷题笔记 25/30

写在前面

这是我参与更文挑战的第25天,活动详情查看:更文挑战

快要毕业了,才发现自己被面试里的算法题吊起来锤。没办法只能以零基础的身份和同窗们共同加入了力扣刷题大军。我的同学们都非常厉害,他们平时只是谦虚,口头上说着自己不会,而我是真的不会。。。乘掘金鼓励新人每天写博客,我也凑个热闹,记录一下每天刷的前两道题,这两道题我精做。我打算每天刷五道题,其他的题目嘛,也只能强行背套路了,就不发在博客里了。

本人真的只是一个菜鸡,解题思路什么的就不要从我这里参考了,编码习惯也需要改进,各位如果想找刷题高手请教问题我觉得去找 宫水三叶的刷题日记 这位大佬比较好。我在把题目做出来之前尽量不去看题解,以免和大佬的内容撞车。

另外我也希望有得闲的大佬提供一些更高明的解题思路给我,欢迎讨论哈!

好了废话不多说开始第二十五天的前两道题吧!

2021.6.25 每日一题

752. 打开转盘锁

这道题感觉挺难的,为什么放中等题里面。。。我使用双向 BFS,这个思路应该是大多数人努努力能想到的,然后看题解居然能用 A*。。。好吧,看来是我题做的不够多。

先根据题意把转旋钮的函数实现一下,转一下旋钮,加一个或者减一个,遇到两头的 0 和 9 是特殊情况,0 减一个实际上是 -1,这时候其实应该减 -9,同理,9 加一个实际上是 10,这时候其实应该加 -9


int steps(int num)
    {
        if(num == 10)
        return -9;
        if(num == -1)
        return -9;
        else return 1;
    }

后面就是双向 BFS 了,能这么用有一个条件,问题的搜索空间肯定是满足局部最优和全局最优是同一个,不然这么双向搜索很容易掉到两个坑里面,这样就再也出不来了。


class Solution {
public:
    int seen[10000];
    int ans = -1;
    bool dead[10000];
    int q[10000];
    int openLock(vector<string>& deadends, string target) { 
        for(auto d : deadends){
            int tmp = stoi(d);
            dead[tmp] = 1;
        }

        if(dead[0])return -1;
        if(target == "0000") return 0;
        int tar=stoi(target);
        bfs(tar);
        return ans;
    }
  
    int steps(int num)
    {
        if(num == 10)
        return -9;
        if(num == -1)
        return -9;
        else return 1;
    }
  
    void bfs(int target)
    {    
        int hh=0,tt=0;

        q[0] = 0;
        while(hh <= tt){
            auto t = q[hh++];
            int prev = t;

            for(int i = 1 ; i <= 1000 ; i *= 10){
                int num = t / i % 10; 
                int temp = t;

                // ++
                int tmp = temp + steps(num + 1) * i;
                if(!seen[tmp] && !dead[tmp]){
                    q[tt++] = tmp;
                    seen[tmp] = seen[prev] + 1;
                }

                // --
                tmp = temp - steps(num - 1) * i;
                if(!seen[tmp] && !dead[tmp]){
                    q[tt++] = tmp;
                    seen[tmp] = seen[prev] + 1;
                }           
            }

            if(seen[target] != 0){
                ans = seen[target];
                break;
            }
        }
    }
};

image.png

可以刷一下运行,这是最好看的结果。

image.png

2021.6.25 每日一题下面的题

剑指 Offer 07. 重建二叉树

这道题经常在面试题的选择题里出现,手画还能说两句,写代码估计要反应一会,我这方面估计还得加强。

给一个前序遍历和中序遍历,把树结构整理出来。根据这两种遍历的特点,首先可以确定整棵树的根节点是中序遍历的第一个点,整棵树最左边的叶子节点是前序遍历的第一个点。然后根据这种有根有左的特点,我们主要就是玩左子树这个概念了。根左右左根右不出现的情况下正好是相反的,那我正好记录一个 root_and_left,暂时不带“右”玩就行。这个 root_and_left 是一个栈,要和另一个指针配合起来。指针 index 是中序遍历上的一个指针,我用它来确定当前在给谁找上级关系。


/**
 * 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:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if (!preorder.size()) {
            return nullptr;
        }
        TreeNode* root = new TreeNode(preorder[0]);
        stack<TreeNode*> stk;
        stk.push(root);
        int inorderIndex = 0;
        for (int i = 1; i < preorder.size(); i++) {
            int preorderVal = preorder[i];
            TreeNode* node = stk.top();
            if (node->val != inorder[inorderIndex]) {
                node->left = new TreeNode(preorderVal);
                stk.push(node->left);
            }
            else {
                while (!stk.empty() && stk.top()->val == inorder[inorderIndex]) {
                    node = stk.top();
                    stk.pop();
                    inorderIndex++;
                }
                node->right = new TreeNode(preorderVal);
                stk.push(node->right);
            }
        }
        return root;
    }
};

image.png

小结

双向BFS

找栈顶,找不到就认主,找到就归队。

参考链接