LeetCode 第33场双周赛 题解

第 33 场双周赛



关注"Grand Theft Algorithm",带你吃透算法题!



## 题目1:[5479. 千位分隔数](https://leetcode-cn.com/problems/thousand-separator/)

思路:模拟

签到题,把整数变为字符串,从后向前遍历,每三位加点即可。

代码:

class Solution {
public:
    string thousandSeparator(int n) {
        string s = to_string(n);	//转为字符串
        reverse(s.begin(), s.end());
        string res;
        int len = s.size();
        for (int i = 0; i < len; i++) {
            res += s[i];
            if (i % 3 == 2 && i + 1 != len) res += ".";
        }
        reverse(res.begin(), res.end());
        return res;
    }
};

复杂度分析:

简单遍历,时间复杂度O(N);

记录结果字符串,空间复杂度O(N)。



关注"Grand Theft Algorithm",带你吃透算法题!



题目2:5480. 可以到达所有点的最少点数目

思路:字符串遍历

签到题2。

要求最少的点能到达其他所有点,找到所有入度为0的点即可。

代码:

class Solution {
public:
    vector<int> findSmallestSetOfVertices(int n, vector<vector<int>>& edges) {
        vector<int> u(n);
        for (auto &e : edges) {
            int x = e[0], y = e[1];
            u[y] ++;
        }
        vector<int> res;
        for (int i = 0; i < n; ++i)
            if (u[i] == 0) res.push_back(i);
        return res;
    }
};

复杂度分析:

遍历数组,时间复杂度为O(N);

空间复杂度为O(N)。



关注"Grand Theft Algorithm",带你吃透算法题!



题目3:5481. 得到目标数组的最少函数调用次数

思路:简单遍历

倒推,求最少的“单个元素减一”和“全部元素除2”的操作次数使得数组元素全部变为0。

不妨一个一个元素考虑:

每一个元素的减1过程都是单独进行的,所以如果当前元素是奇数,就必须要进行减一操作,最后需要将所有元素的减一操作次数相加;

而每个元素的除2操作是整个数组共同进行的,而某一个元素变成0之后,其他元素再怎么折腾,不管多少次除2操作都不会对这个元素有影响,所以最后只需要求出所有元素的除二次数的最大值。

代码:

class Solution {
public:
    int minOperations(vector<int>& nums) {
        int res = 0, pos = 0;
        for(int x : nums) {
            int now = 0;
            while(x) {
                if(x % 2 == 1) {
                    res++;	// 减1次数
                    x--;
                } else {
                    now++;
                    x /= 2;
                }
            }
            pos = max(pos, now);	// 除2次数
        }
        res += pos;
        return res;
    }
};

复杂度分析:

数组遍历,时间复杂度为O(N);

维护两个变量,空间复杂度为O(1)。



关注"Grand Theft Algorithm",带你吃透算法题!



题目4:5482. 二维网格图中探测环

思路:深度优先搜索

要在二维地图里寻找某种不重复路径,且需要判断全部路径中是否有满足条件(即成环)的路径,用深度优先搜索。

判断环路,说明最后要回到之前遍历过的某一点,为了防止最后两个点来回搜索,要在参数中记录父节点(即探索当前位置的前一个位置)。

实现细节:

深搜过程中,首先判断拓展节点与父节点是否相同,若相同说明搜索在两个点来回进行,直接pass掉。

其次判断拓展节点是否已经遍历过,若遍历过且不为父节点,说明找到了之前遍历过的某一点,满足成环条件,返回 t r u e true true

若没有遍历过,则对拓展节点进行新一次的深度优先搜索。若所有拓展节点都深搜完成且未找到成环路径,则返回 f a l s e false false

代码:

class Solution {
public:
    int n, m;
    int dx[4] = {-1, 0, 1, 0};
    int dy[4] = {0, -1, 0, 1};
    bool in_grid(int x, int y) {
        return x >= 0 && x < n && y >= 0 && y < m;
    }
    
    bool dfs(int x, int y, int fx, int fy, vector<vector<char>>& grid, vector<vector<bool>>& visit) {
        visit[x][y] = true;
        for(int i = 0; i < 4; i++) {
            int nx = x + dx[i], ny = y + dy[i];
            if(nx == fx && ny == fy) {
                continue;
            }
            if(in_grid(nx, ny) && grid[nx][ny] == grid[x][y]) {
                if(visit[nx][ny]) {
                    return true;
                }
                if(dfs(nx, ny, x, y, grid, visit)) {
                    return true;
                }
            }
        }
        return false;
    }

    bool containsCycle(vector<vector<char>>& grid) {
        n = grid.size();
        m = grid[0].size();
        vector<vector<bool>> visit(n, vector<bool>(m, 0));
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                if(!visit[i][j]) {
                    if(dfs(i, j, -1, -1, grid, visit)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
};

复杂度分析:

深度优先搜索,总时间复杂度为O(NM);

维护遍历过程记录表,空间复杂度为O(NM)。

猜你喜欢

转载自blog.csdn.net/weixin_42396397/article/details/108179415