https://leetcode.com/contest/biweekly-contest-146/

3392. Count Subarrays of Length Three With a Condition

Tag: Array

class Solution {
public:
    int countSubarrays(vector<int>& nums) {
        int n = nums.size();
        int ans = 0;
        for (int i = 2; i < n; i++)
            ans += (nums[i - 2] + nums[i]) * 2 == nums[i - 1];
        return ans;
    }
};

Time Complexity: O(n)
Space: O(1)

3393. Count Paths With the Given XOR Value

Tag:DP

typedef long long ll;
class Solution {
public:
    ll mod = 1e9 + 7;
    int countPathsWithXorValue(vector<vector<int>>& grid, int target) {
        int m = grid.size(), n = grid[0].size();
        vector<vector<vector<ll>>> f(m, vector<vector<ll>>(n, vector<ll>(16, 0)));
        f[0][0][grid[0][0]] = 1;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (i - 1 >= 0) {
                    for (int k = 0; k < 16; k++)
                        f[i][j][grid[i][j] ^ k] += f[i - 1][j][k];
                }
                if (j - 1 >= 0) {
                    for (int k = 0; k < 16; k++)
                        f[i][j][grid[i][j] ^ k] += f[i][j - 1][k];
                }
                for (int k = 0; k < 16; k++) f[i][j][k] %= mod;
            }
        }
        return f[m - 1][n - 1][target];
    }
};

Time Complexity: O(m * n * 16)
Space: O(m * n * 16)

算是經典 DP 的稍微變形,需要注意一下他的數值限制就可以發現他希望你使用的做法,基本上看到他的數字都不大就知道可以暴力 DP 了。

再來就是如果 Bottom-up 的 DP 不知道怎麼做也可以考慮使用 Top-down的 DP 會比較好理解。

Top-down: 會把 DP 類型的題目使用遞迴的方式解出來,同時他會需要搭配 memory 的方式紀錄曾經算過的東西。
Bottom-up: 會把 DP 類型的題目使用迴圈的方式解出來。

3394. Check if Grid can be Cut into Sections

Tag: Sort

class Solution {
public:
    static const bool cmpY(vector<int> &a, vector<int> &b) {
        if (a[1] != b[1]) return a[1] < b[1];
        return a[3] < b[3];
    }
    static const bool cmpX(vector<int> &a, vector<int> &b) {
        if (a[0] != b[0]) return a[0] < b[0];
        return a[2] < b[2];
    }
    bool checkValidCuts(int sz, vector<vector<int>>& rectangles) {
        int n = rectangles.size();
        sort(rectangles.begin(), rectangles.end(), cmpY);
        int cnt = 0;
        int l = 0, r = 1;
        while (r < n) {
            while (rectangles[l][3] <= rectangles[r][1]) {
                l += 1;
            }
            cnt += l == r;
            if (cnt == 2) return true;
            r += 1;
        }

        sort(rectangles.begin(), rectangles.end(), cmpX);
        cnt = 0;
        l = 0, r = 1;
        while (r < n) {
            while (l < r && rectangles[l][0] < rectangles[r][0] && rectangles[l][2] <= rectangles[r][0]) {
                l += 1;
            }
            cnt += (l == r);
            if (cnt == 2) return true;
            r += 1;
        }
        return false;
    }
};

n = rectangles.size
Time Complexity: O(nlogn)
Space: O(1)

基本上我們可以把水平與垂直分開處理,只要你知道水平怎麼處理就會知道垂直怎麼解了。核心部分就在我們需要分別對起始的 x 或是 y 進行排序,然後使用雙指針就可以知道在哪個地方進行切割。