1024 极限挑战

作为一个大四老萌新,第一次过1024,一时不知道给这天涂抹啥样的颜色。贫穷(各种意义上)限制了我的操作空间(哭)。但毕竟是1024嘛,一年也就一次,我想尽可能让这 1 366 \frac{1}{366} 3661与众不同一些。于是给自己安排了一些 ⌈ \lceil 全天挑战 ⌋ \rfloor

尽可能在 ⌈ \lceil 0 ⌋ \rfloor 次错误的前提下于leetcode上随机AC ⌈ \lceil 24 ⌋ \rfloor 题,然后根据完成的题目的难度折合成百分制进行评分(简单 → \rightarrow 3,中等 → \rightarrow 4, 困难 → \rightarrow 5 ),满分120,每不通过一次扣1分(扣分无下限)。

⌈ \lceil 1 ⌋ \rfloor 篇博客(正如您现在所见)记录"今日的颜色"

挑战 Leetcode 24题

下面我将把今天AC过的题目列出来,问题详情可以点击题目标题链接,简要说下思路和算法运行时间。

01 剑指 Offer 03. 数组中重复的数字

题目链接

【难度】简单
【得分】2/3
【题目翻译】找出含n个元素的数组中的任一重复数字,且数字范围是[0, n-1], 2 ≤ n ≤ 100000 2 \le n \le 100000 2n100000
【思路】用桶方法对号入座。
【时/空复杂度】 O ( N ) O(N) O(N) O ( N ) O(N) O(N) N N N表示所给容器大小。
【执行情况】
在这里插入图片描述【代码】

class Solution {
    
    
public:
    int findRepeatNumber(vector<int>& nums) {
    
    
        vector<int> arr(nums.size(), 0);
        for (int a: nums){
    
    
            if(arr[a])
                return a;
            else
                ++arr[a];
        }
        return 0;
    }
};

【失分原因】把循环体中的arr错写成nums了。

02 1020. 飞地的数量

题目链接

【难度】中等
【得分】2/4
【题目翻译】找不与边界陆地相连的陆地数
【思路】预处理+BFS
【时/空复杂度】: O ( N M ) O(NM) O(NM) O ( N M ) O(NM) O(NM),其中 N N N M M M分别表示二维数组行、列。
【执行情况】

在这里插入图片描述
【代码】

class Solution {
    
    
public:
    int n, m;
    bool isOnBorder(int x, int y){
    
    
        if(x>0 && x<n-1 && y>0 && y<m-1)
            return false;
        return true;
    }
    int numEnclaves(vector<vector<int>>& A) {
    
    
        n = A.size();
        m = A[0].size();
        int total=0; //陆地总数
        int ans=0; //与边界点相连的单元格数
        queue<pair<int, int>> que;
        vector<vector<bool>> mark(n, vector<bool>(m, 0));
        for (int i=0; i<n; ++i){
    
    
            for (int j=0; j<m; ++j){
    
    
                if(A[i][j] == 1){
    
    
                    ++total;
                    if(isOnBorder(i, j)){
    
     //边界点
                        mark[i][j] = true;
                        que.push(make_pair(i, j));
                        ++ans;
                    }
                }
            }
        }
       //cout<<ans<<endl;
        const int dx[4]{
    
    0, 1, 0, -1};
        const int dy[4]{
    
    1, 0, -1, 0};
        while (!que.empty()){
    
    
            auto pos = que.front();
            que.pop();
            int x=pos.first, y=pos.second;
            for (int k=0; k<4; ++k){
    
    
                int mx = x + dx[k];
                int my = y + dy[k];
                if(mx<0 || mx>=n || my<0 || my>=m 
                    || mark[mx][my] || A[mx][my] == 0)
                    continue;
                if(!isOnBorder(mx, my)){
    
    //边界点只算一次
                    mark[mx][my] = true;
                    que.push(make_pair(mx, my));
                    ++ans; //与边界相连的点+1
                }              
            }
        }
        //cout<<total<<endl;
        //cout<<ans<<endl;
        ans = total - ans;
        return ans;   
    }
};

【失分原因】

  1. 把边界陆地重复算了几次,且mark进行标记的程序位置不对;
  2. 审题出错:错误认为为行、列数相同
03 1015. 可被 K 整除的最小整数

题目链接

【难度】中等
【得分】3/4
【题目翻译】返回由n个1组成的可以被K整除的正整数的位数,这些正整数的集合为 { 1 , 11 , 111 , 1111 , . . . } \{1, 11, 111, 1111, ...\} { 1,11,111,1111,...}
【思路】找到前后两个数的关系:比如 1111 = 10 ∗ 111 + 1 1111= 10*111 + 1 1111=10111+1,然后考虑取余。注意不能被整除的条件判断:若余数之前出现过,则表示不可能被整除。
【时/空复杂度】: O ( K ) O(K) O(K) O ( K ) O(K) O(K),其中 K K K为除数,因为最坏情况为:每一轮出现不同的余数,而余数最多有 K K K个。
【执行情况】

在这里插入图片描述
【代码】

class Solution {
    
    
public:
    int smallestRepunitDivByK(int K) {
    
    
        int ans=1;
        int rem=1 % K;
        vector<bool> mark(K, 0);
        // rem = (pre_remain*10 + 1) % K
        //特例->6
        while (rem){
    
    
            mark[rem] = true;
            int cur_rem = (10*rem+1) % K;
            if(mark[cur_rem])
                return -1;
            rem = cur_rem;
            ++ans;
        }
        return ans;
    }
};

【失分原因】不能被整除时的条件考虑错了,从而永远跳不出循环。

04 529. 扫雷游戏

题目链接

【难度】中等
【得分】4/4
【题目翻译】模拟扫雷游戏,根据点击的块类型进行不同的操作。
【思路】与第2题思路差不多:BFS,只不过斜对角线也得考虑。虽然这题一遍过,但耗了大量时间,原因在于:①测试用例JSON解析有误(直接从题目示例复制粘贴的),花了大量时间debug,这告诉我们不要随意复制,手动输入最稳;②注意附近有雷的块不能继续递归下去,因此判断雷的数目需要在加入队列操作之前!
【时/空复杂度】: O ( N M ) O(NM) O(NM) O ( N M ) O(NM) O(NM),其中 N N N M M M分别表示二维数组行、列。
【执行情况】
在这里插入图片描述

【代码】

class Solution {
    
    
public:
    int n, m;
    vector<vector<char>> updateBoard(vector<vector<char>>& board,
     vector<int>& click) {
    
    
        if(board[click[0]][click[1]] == 'M'){
    
     //直接踩雷
            board[click[0]][click[1]] = 'X';
            return board;
        }
        else{
    
     //点击'E'处
            n = board.size();
            m = board[0].size();
            queue<pair<int, int>> que;
            vector<vector<bool>> mark(n, vector<bool>(m, 0));
            que.push(make_pair(click[0], click[1]));
            mark[click[0]][click[1]] = true;
            const int dx[8]{
    
    0, 1, 0, -1, 1, 1, -1, -1};
            const int dy[8]{
    
    1, 0, -1, 0, 1, -1, -1, 1};
            while (!que.empty()){
    
    
                auto pos = que.front();
                que.pop();
                int x = pos.first, y = pos.second;
                int cnt=0; //周围炸弹数
                for (int k=0; k<8; ++k){
    
    
                    int mx=x+dx[k], my=y+dy[k];
                    if(mx<0 || mx>=n || my<0 || my>=m)
                        continue;
                    if(board[mx][my] == 'M')
                        ++cnt;      
                }
                if(cnt)
                    board[x][y] = '0' + cnt;
                else{
    
     //'B'
                    //把一些节点加入队列
                    for (int k=0; k<8; ++k){
    
    
                        int mx=x+dx[k], my=y+dy[k];
                        if(mx<0 || mx>=n || my<0 || my>=m
                            || mark[mx][my])
                            continue;
                        if(board[mx][my] == 'E'){
    
    
                            mark[mx][my] = true;
                            que.push(make_pair(mx, my));
                        }                    
                    }
                    board[x][y] = 'B';
                }
            }
            return board;
        }
    }
};
05 501. 二叉搜索树中的众数

题目链接

【难度】简单
【得分】1/3
【题目翻译】给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
【思路】中序遍历得到的序列为非降序序列,在遍历过程中记录当前数字出现次数和过程最大次数,并更新存储众数的容器。
【时/空复杂度】: O ( N ) O(N) O(N) O ( H ) O(H) O(H),其中 N N N为节点数目, H H H为递归深度,最坏情况下空间开销为 O ( N ) O(N) O(N)
【执行情况】
在这里插入图片描述

【代码】

/**
 * 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:
    int pre;
    int cnt, maxn;
    void inorder(TreeNode* root, vector<int>& v){
    
    
        if(!root)
            return;
        inorder(root->left, v);
        if(pre == root->val){
    
    
            ++cnt;
            if(cnt > maxn){
    
    
                maxn = cnt;
                v.clear();
                v.push_back(pre);
            }
            else if(cnt == maxn){
    
    
                v.push_back(pre);
            }
        }
        else{
    
    
            cnt = 1;
            if(cnt >= maxn){
    
    
                v.push_back(root->val);
            }           
        }
        pre = root->val;
        inorder(root->right, v);
    }
    vector<int> findMode(TreeNode* root) {
    
    
        vector<int> nums;
        if(!root)
            return nums;
        if(root->val == INT_MIN)
            pre = root->val + 1;
        else
            pre = root->val - 1;
        cnt=0;
        maxn = 0;
        inorder(root, nums);
        return nums;
    }
};

【失分原因】

  1. 没考虑溢出的测试边界(pre可能溢出);
  2. 没考虑空树
06 557. 反转字符串中的单词 III

题目链接

【难度】简单
【得分】3/3
【题目翻译】给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序,其中不存在连续的空格。
【思路】逐个单词翻转,原地修改
【时/空复杂度】: O ( N ) O(N) O(N) O ( 1 ) O(1) O(1),其中 N N N为字符串长度
【执行情况】
在这里插入图片描述

【代码】

class Solution {
    
    
public:
    void revStr(string& s, int L, int R){
    
    
        if(L>=R)
            return;
        int mid = (L+R) / 2;
        for (int i=L; i<=mid; ++i){
    
    
            char temp = s[i];
            s[i] = s[R+L-i];
            s[R+L-i] = temp;
        }
    }
    string reverseWords(string s) {
    
    
        int n = s.length();
        int start=0, end=0;
        while (end < n){
    
    
            while (end<n && s[end] != ' ')
                ++end;
            //cout<<end-1<<endl;
            revStr(s, start, end-1);
            end++;
            start = end;
        }
        return s;
    }
};
07 1351. 统计有序矩阵中的负数

题目链接

【难度】简单
【得分】3/3
【题目翻译】给你一个 N * M 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。请你统计并返回 grid负数 的数目。
【思路】对每行(列)二分查找到第一个负数,即可得到该行(列)负数个数,然后求和即可。
【时/空复杂度】: O ( N l o g M ) O(NlogM) O(NlogM) O ( 1 ) O(1) O(1),其中 N N N M M M分别为矩阵的行和列。
【执行情况】
在这里插入图片描述

【代码】

class Solution {
    
    
public:
    int binarySearch(const vector<int>& v, int m){
    
    
        int left = 0, right = m-1;
        while (left <= right){
    
    
            int mid = (left+right) / 2;
            if(v[mid] < 0)
                right = mid-1;
            else
                left = mid+1;
        }
        return right+1;
    }
    int countNegatives(vector<vector<int>>& grid) {
    
    
        int n = grid.size();
        int m = grid[0].size();
        int ans=0;
        for (int i=0; i<n; ++i){
    
    
            ans += m-binarySearch(grid[i], m);
        }
        return ans;
    }
};
08 剑指 Offer 05. 替换空格

题目链接

【难度】简单
【得分】3/3
【题目翻译】请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
【思路】建立一个返回串,搬运非空格字符,遇到空字符纳入"%20"即可。
【时/空复杂度】: O ( N ) O(N) O(N) O ( N ) O(N) O(N),其中 N N N为字符串长度。
【执行情况】
在这里插入图片描述

【代码】

class Solution {
    
    
public:
    string replaceSpace(string s) {
    
    
        string ans="";
        for (auto& ch: s){
    
    
            if(ch == ' '){
    
    
                ans += "%20";
            }
            else{
    
    
                char chs[] = {
    
    ch, '\0'};
                ans += chs;
            }
        }
        return ans;
    }
};
09 868. 二进制间距

题目链接

【难度】简单
【得分】3/3
【题目翻译】求正整数N二进制表示中两个1的最远距离。
【思路】这题我小看了。可能是做了一天了脑袋炸了,以至于折腾了半天才想明白:一位位的处理,最好画个树状图把情况理清楚,否则大脑一团浆糊。
【时/空复杂度】: O ( C ) O(C) O(C) O ( C ) O(C) O(C),其中 C C C为正整数二进制最大位数,这里 C C C取32。
【执行情况】
在这里插入图片描述

【代码】

class Solution {
    
    
public:
    int binaryGap(int n) {
    
    
        int bin[32]{
    
    0};
        int p=0;
        while (n){
    
    
            bin[p] = (n&1);
            ++p;
            n >>= 1;
        }
        int left = -1, right = -1, pre = bin[0];
        if(bin[0]){
    
    
            left = 0;
        }
        int maxn = 0;
        for (int i=1; i<p; ++i){
    
    
            if(pre == 0){
    
    
                if(bin[i] == 0){
    
    
                    if(left != -1){
    
    
                        right = i;
                    }
                }
                else{
    
    
                    if(left == -1){
    
    
                        left = i;
                    }
                    else{
    
    
                        right = i;
                        maxn = max(maxn, right - left);
                        left = right;
                    }
                }
            }
            else if(pre == 1){
    
    
                if(bin[i] == 0){
    
    
                    right = i;
                }
                else{
    
    
                    maxn = max(maxn, 1);
                    left = i;
                    right = i;
                }
            }
            pre = bin[i];
        }
        return maxn;
    }
};
10 LCP 07. 传递信息

题目链接

【难度】简单
【得分】3/3
【题目翻译】有向图中起、终点之间的路径长度恰好为 K K K的方案数(可以重复经过同一节点)。
【思路】建立有向图,然后不带访问标记的DFS。
【时/空复杂度】: O ( N K ) O(N^K) O(NK) O ( N 2 ) O(N^2) O(N2),其中 N N N为节点数, K K K为轮数,最坏情况为:有向完全图;空间开销主要为建立有向图。
【执行情况】
在这里插入图片描述

【代码】

class Solution {
    
    
public:
    vector<vector<int>> graph;
    int target;
    int N;
    void dfs(int k, int cur, int& ans){
    
    
        if(k >= target){
    
    
            if(cur == N-1){
    
    
                ++ans;
            }
            return;
        }
        for (auto& x: graph[cur]){
    
    
            dfs(k+1, x, ans);
        }
    }
    int numWays(int n, vector<vector<int>>& relation, int k) {
    
    
        graph = vector<vector<int>>(n);
        target = k;
        N = n;
        int ans=0;
        for (vector<int>& v: relation){
    
    
            graph[v[0]].push_back(v[1]);
        }
        for (auto& x: graph[0]){
    
    
            dfs(1, x, ans);
        }   
        return ans;
    }
};
11 137. 只出现一次的数字 II

题目链接

【难度】中等
【得分】4/4
【题目翻译】给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
【思路】哈希表。我想过位运算,但是实在不知道异或搭配啥运算才能区分出现1次和出现3次的元素,所以放弃了(如果用位运算的话空间开销为 O ( 1 ) O(1) O(1))。
【时/空复杂度】: O ( N ) O(N) O(N) O ( N ) O(N) O(N),其中 N N N为数组容器大小。
【执行情况】
在这里插入图片描述

【代码】

class Solution {
    
    
public:
    int singleNumber(vector<int>& nums) {
    
    
        map<int, int> hash;
        for (int i=0; i<nums.size(); ++i){
    
    
            hash[nums[i]]++;
        }
        for (auto& item: hash){
    
    
            if(item.second == 1)
                return item.first;
        }
        return -1;
    }
};
12 1302. 层数最深叶子节点的和

题目链接

【难度】中等
【得分】4/4
【题目翻译】给你一棵二叉树,请你返回层数最深的叶子节点的和。
【思路】两遍DFS:获得树高度;把节点深度为树高的节点值求和。不过还可以更简单,一次DFS就能搞定,之后再看看吧。
【时/空复杂度】: O ( N ) O(N) O(N) O ( H ) O(H) O(H),其中 N N N为树的节点总数, H H H为递归深度,即树的高度,最坏时空间开销趋于 O ( N ) O(N) O(N)
【执行情况】
在这里插入图片描述

【代码】

/**
 * 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:
    int level, maxn;
    void dfs1(TreeNode* root){
    
    
        if(!root)
            return;
        maxn = max(maxn, level);
        level++;
        dfs1(root->left);
        dfs1(root->right);
        level--;   
    }
    void dfs2(TreeNode* root, int& ans){
    
    
        if(!root)
            return;
        if(level == maxn){
    
    
            ans += root->val;
        }
        ++level;
        dfs2(root->left, ans);
        dfs2(root->right, ans);
        --level;
    }
    int deepestLeavesSum(TreeNode* root) {
    
    
        if(!root)
            return 0;
        level = 1;
        maxn = 1;
        dfs1(root);
        int ans=0;
        level = 1;
        dfs2(root, ans);
        return ans;
    }
};
13 6. Z 字形变换

题目链接

【难度】中等
【得分】3/4
【题目翻译】将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
【思路】找规律。过程中注意第一行和最后一行的处理;另外考虑只有1行的情况。
【时/空复杂度】: O ( N ) O(N) O(N) O ( 1 ) O(1) O(1),其中 N N N为字符串长度。
【执行情况】
在这里插入图片描述

【代码】

class Solution {
    
    
public:
    string convert(string s, int numRows) {
    
    
        if(numRows == 1)
            return s;
        string ret = "";
        int n = s.length();
        for (int i=0; i<numRows; ++i){
    
    
            int k = 2*(numRows-1-i);            
            int idx = i;
            while (idx<n){
    
    
                ret.push_back(s[idx]);
                if(i == numRows-1){
    
    
                    k = 2*(numRows-1);
                    idx += k;
                }
                else
                    idx += k;
                if(i!= 0 && i!= numRows-1)
                    k = 2*(numRows-1)-k;
            }
        }
        return ret;
    }
};

【失分原因】没考虑只有1行的情况,陷入无限循环。。。

14 104. 二叉树的最大深度

题目链接

【难度】简单
【得分】3/3
【题目翻译】给定一个二叉树,找出其最大深度。
【思路】半分钟搞定,递归即可。
【时/空复杂度】: O ( N ) O(N) O(N) O ( H ) O(H) O(H),其中 N N N为节点数目, H H H为树的高度,也即递归深度,空间开销最坏趋于 O ( N ) O(N) O(N)
【执行情况】
在这里插入图片描述

【代码】

/**
 * 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:
    int maxDepth(TreeNode* root) {
    
    
        if(!root)
            return 0;
        int left = maxDepth(root->left);
        int right = maxDepth(root->right);
        return max(left, right) + 1;
    }
};
15 剑指 Offer 57 - II. 和为s的连续正数序列

题目链接

【难度】简单
【得分】3/3
【题目翻译】输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
【思路】只剩下1小时20分钟了。。。脑力用尽了,只能使用暴力DFS了。
【时/空复杂度】: O ( N N ) O(N\sqrt{N}) O(NN ) O ( H ) O(H) O(H),其中 N N N t a r g e t target target H H H为递归深度,空间开销最坏趋于 O ( N ) O(\sqrt{N}) O(N )
【执行情况】
在这里插入图片描述

【代码】

class Solution {
    
    
public:
    vector<int> temp;
    vector<vector<int>> ret;
    void dfs(int cur, int k){
    
    
        temp.push_back(cur);
        if(k == 0){
    
    
            ret.push_back(temp);
            temp.pop_back();
            return;
        }
        else if(k<0)
            return;     
        dfs(cur+1, k-cur-1);   
    }
    vector<vector<int>> findContinuousSequence(int target) {
    
    
        if(target == 1)
            return ret;
        for (int i=1; i <= target / 2; ++i){
    
    
            temp.clear();
            dfs(i, target-i);
        }
        return ret;
    }
};
16 397. 整数替换

题目链接

【难度】中等
【得分】-1/4
【题目翻译】给定一个正整数 n,你可以做如下操作:

  1. 如果 n 是偶数,则用 n / 2替换 n。
  2. 如果 n 是奇数,则可以用 n + 1或n - 1替换 n。
    问:n 变为 1 所需的最小替换次数是多少?

【思路】递归解决,注意最大值、n为1等边界情况。另外,记忆化搜索会超时。
【时/空复杂度】: O ( l o g N ) O(logN) O(logN) O ( 1 ) O(1) O(1),其中 N N N n n n,这里的时间复杂度分析不太确定
【执行情况】
在这里插入图片描述
在这里插入图片描述

【代码】

class Solution {
    
    
public:
    vector<int> temp;
    vector<vector<int>> ret;
    void dfs(int cur, int k){
    
    
        temp.push_back(cur);
        if(k == 0){
    
    
            ret.push_back(temp);
            temp.pop_back();
            return;
        }
        else if(k<0)
            return;     
        dfs(cur+1, k-cur-1);   
    }
    vector<vector<int>> findContinuousSequence(int target) {
    
    
        if(target == 1)
            return ret;
        for (int i=1; i <= target / 2; ++i){
    
    
            temp.clear();
            dfs(i, target-i);
        }
        return ret;
    }
};

挑战情况

现在是23:30,目前总共AC了16道题,即题目完成度为16/24。做题数目上没有达成目标,当然有一部分原因是开始得晚:今日上午11点左右开始的,最主要原因还是历练不够,考虑问题不够全面。这个过程中除了以下题目没弄出来或不想做而跳过外,其余题目基本没跳(当然,困难题跳了)。

那么就做个简单的结算吧~
本次挑战一共完成了 9 ⌈ \lceil 简单 ⌋ \rfloor 题,7 ⌈ \lceil 中等 ⌋ \rfloor 题, 0 ⌈ \lceil 困难 ⌋ \rfloor

  1. 按题目完成率:16/24 → \rightarrow 66.7 % 66.7\% 66.7%
  2. 按总分120,总共得分:43/120 → \rightarrow 36/100。不及格嘿(哭)~
  3. 按照已做题目的得分:43/55 → \rightarrow 78/100,看着舒服些了~

另外,过程中动手但未提交或者直接跳过的题目列表:

  1. 611 有效三角形

  2. 808 分汤

  3. 703 数据流中的第 K 大元素

  4. 669 修剪二叉搜索树

  5. 264 丑数II

  6. 1030 距离顺序排列矩阵单元格

总之,还有很多需要改进的地方,不论是解题思路还是经验积累~在今后的日子一定得再接再厉!!

猜你喜欢

转载自blog.csdn.net/weixin_42430021/article/details/109255412