LeetCode(Weekly Contest 188)题解

0. 前言

1. 题解

1.1 5404. 用栈操作构建数组(1441. Build an Array With Stack Operations)

class Solution {
public:
    vector<string> buildArray(vector<int>& target, int n) {
        int cur = 0, cnt = target.size();
        vector<string> ans;
        for (int i = 1 ; i <= n ; i++) {
            if (cur == cnt)   break;
            if (target[cur] == i) {
                ans.push_back("Push");
                cur++;
            } else {
                ans.push_back("Push");
                ans.push_back("Pop");
            }
        }
        return ans;
    }
};

1.2 5405. 形成两个异或相等数组的三元组数目(1442. Count Triplets That Can Form Two Arrays of Equal XOR)

class Solution {
public:
    int countTriplets(vector<int>& arr) {
        int n = arr.size();
        vector<int> xors = vector<int>(n+1, 0);
        xors[1] = arr[0];
        for (int i = 2 ; i <= n ; i++) {
            xors[i] = arr[i-1] ^ xors[i-1];
        }
        int ans = 0;
        for (int i = 0 ; i < n ; i++) {
            for (int j = i+1 ; j < n ; j++) {
                for (int k = j ; k < n ; k++) {
                    if (xors[j] ^ xors[i] == xors[k+1] ^ xors[j]) {
                        ans++;
                    }
                }
            }
        }
        return ans;
    }
};
  • 哈希代码如下:
class Solution {
public:
    int countTriplets(vector<int>& arr) {
        int n = arr.size();
        unordered_map<int, vector<int>> cnt;
        int x = 0, ans = 0;
        cnt[0] = vector<int>();
        cnt[0].push_back(0);
        for (int i = 1 ; i <= n ; i++) {
            x ^= arr[i-1];
            if (cnt.find(x) == cnt.end()) {
                cnt[x] = vector<int>();
            }
            for (auto j : cnt[x]) {
                // cout << j+1 << "->" << i << endl;
                ans += (i - j - 1);
            }
            cnt[x].push_back(i);
        }
        return ans;
    }
};

1.3 5406. 收集树上所有苹果的最少时间(1443. Minimum Time to Collect All Apples in a Tree)

class Solution {
public:
    bool dfs1(int cur, vector<vector<int>>& adj, vector<bool>& hasApple, vector<bool>& need) {
        need[cur] = hasApple[cur];
        if (0 == (int)adj[cur].size()) {
            return need[cur];
        }
        for (auto next : adj[cur]) {
            if (dfs1(next, adj, hasApple, need)) {
                need[cur] = true;
            }
        }
        return need[cur];
    }
    int dfs2(int cur, vector<vector<int>>& adj, vector<bool>& need, vector<int>& dp) {
        if (0 == (int)adj[cur].size()) {
            return 0;
        }
        cout << cur << endl;
        if (dp[cur])    return dp[cur];
        for (auto next : adj[cur]) {
            if (!need[next])    continue;
            // cout << cur << "->" << next << endl;
            dp[cur] += 2 + dfs2(next, adj, need, dp);
            // cout << "dp[" << cur << "] = " << dp[cur] << endl;
        }
        return dp[cur];
    }
    int minTime(int n, vector<vector<int>>& edges, vector<bool>& hasApple) {
        vector<int> dp = vector<int>(n, 0);
        vector<bool> need = vector<bool>(n, false);
        vector<vector<int>> adj = vector<vector<int>>(n, vector<int>());
        for (auto v : edges) {
            adj[v[0]].push_back(v[1]); 
        }
        dfs1(0, adj, hasApple, need);
        dfs2(0, adj, need, dp);
        return dp[0];
    }
};
  • 七行代码方法如下:
class Solution {
public:
    int minTime(int n, vector<vector<int>>& edges, vector<bool>& hasApple) {
        for (int i = (int)edges.size()-1 ; i >= 0 ; i--) {
            if (hasApple[edges[i][1]] == true) {
                hasApple[edges[i][0]] = true;
            }
        }
        int ans = 0;
        for (int i = (int)edges.size()-1 ; i >= 0 ; i--) {
            if (hasApple[edges[i][1]]) ans += 2;
        }
        return ans;
    }
};

1.4 5407. 切披萨的方案数(1444. Number of Ways of Cutting a Pizza)

  • 中文版题目描述:https://leetcode-cn.com/problems/number-of-ways-of-cutting-a-pizza/
  • 英文版题目描述:https://leetcode.com/problems/number-of-ways-of-cutting-a-pizza/
  • 思路:dp,dp[i][j][k] 表示切了 k-1 刀,剩余披萨左上角第 i 行 j 列为左上角的切法数量,初始化 dp[1][1][1] = 1
    • 二层遍历剩余左上角,然后逐行判断是否可以切,在更新以切口处为左上角的披萨,切了 k 刀的切法,然后再逐列切,方法同上,复杂度为 O(N^4)
    • 判断切口两端是否 'A',可以通过容斥原理计算,nums[i][j] 表示以第 i 行 j 列为右下角,第 1 行 1 列为左上角的 'A' 大数量
  • 二分法代码如下:
class Solution {
public:
    int numA(int r, int c, vector<vector<int>>& nums, int ru, int cu) {
        // cout << "numA:" << ru << " " << cu << " " << r << " " << c << endl;
        // cout << nums[r][c] << "-" << nums[ru-1][c] << "-" << nums[r][cu-1] << "-" << nums[ru-1][cu-1] << endl;
        return nums[r][c] - (nums[ru-1][c] + nums[r][cu-1] - nums[ru-1][cu-1]);
    }
    int ways(vector<string>& pizza, int k) {
        int  r = (int)pizza.size(), c = (int)pizza[0].length(), mod = 1000000007;
        vector<vector<int>> nums = vector<vector<int>>(r+1, vector<int>(c+1, 0));
        for (int i = 1 ; i <= r ; i++) {
            for (int j = 1 ; j <= c ; j++) {
                nums[i][j] = nums[i-1][j] + nums[i][j-1] - nums[i-1][j-1] + (int)(pizza[i-1][j-1] == 'A');
            }
        }
        vector<vector<vector<int>>> dp = vector<vector<vector<int>>>(r+1, vector<vector<int>>(c+1, vector<int>(k+1)));
        dp[1][1][1] = 1;
        for (int cut = 2 ; cut <= k ; cut++) {
            for (int i = 1 ; i <= r ; i++) {
                for (int j = 1 ; j <= c ; j++) {
                    if (dp[i][j][cut-1] == 0) continue;
                    int cntIJ = numA(r, c, nums, i , j);
                    for (int l = i ; l < r ; l++) {
                        int cntLJ = numA(r, c, nums, l+1, j);
                        if (cntIJ - cntLJ > 0 && cntLJ > 0) {
                            dp[l+1][j][cut] +=  dp[i][j][cut-1];
                            dp[l+1][j][cut] %= mod;
                        }
                    }
                    for (int l = j ; l < c ; l++) {
                        int cntIL = numA(r, c, nums, i, l+1);
                        if (cntIJ - cntIL > 0 && cntIL > 0) {
                            dp[i][l+1][cut] += dp[i][j][cut-1];
                            dp[i][l+1][cut] %= mod;
                        }
                    }
                }
            }
        }

        int ans = 0;
        for (int i = 1 ; i <= r ; i++) {
            for (int j = 1 ; j <= c ; j++) {
                ans += dp[i][j][k];
                ans %= mod;
            }
        }
        return ans;
    }
};

3. 参考文献 

上一篇:2021年将新推188部动画,爱优腾加上B站你选谁?


下一篇:58红包扫雷系统原生开发,源码待售快速搭建