LeetCode 力扣周赛 254

74 阅读2分钟

周赛传送门

5843. 作为子字符串出现在单词中的字符串数目

思路std::string::find

时间复杂度O(nm)O(n*m)nnpatternspatterns 的字符总数,mmwordword 的字符总数。

根据 std::string::find 返回值是否等于std::string::npos,可以快速判断 patternsipatterns_i 是否为 wordword 的子串。

class Solution {
public:
    int numOfStrings(vector<string>& patterns, string word) {
        int cnt = 0;
        for (const auto & c : patterns) {
            if (word.find(c) != std::string::npos) {
                cnt++;
            }
        }
        return cnt;
    }
};

5832. 构造元素不等于两相邻元素平均值的数组

思路:排序,交换

时间复杂度O(nlgn)O(n\lg n)

考虑一个下标从 00 开始的,严格递增的序列 numsnums。将其中 i=2,4,6,8...i = 2,4,6,8... 的元素 numsinums_inumsi1nums_{i-1} 进行交换。交换后:

  • i=1,3,5,7...i = 1,3,5,7... 处均满足 numsi1<numsi>numsi+1nums_{i-1} \lt nums_i \gt nums_{i+1}
  • i=2,4,6,8...i = 2,4,6,8... 处均满足 numsi1>numsi<numsi+1nums_{i-1} \gt nums_i \lt nums_{i+1}

显然,交换后任意位置均满足要求。因此,可先对 numsnums 进行排序,然后按上述流程处理。

class Solution {
public:
    vector<int> rearrangeArray(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        for (int i = 2; i < nums.size(); i += 2) {
            swap(nums[i-1], nums[i]);
        } 
        return nums;
    }
};

5844. 数组元素的最小非零乘积

思路:贪心,快速幂

时间复杂度O(P)O(P)

首先思考怎样交换才能使乘积变小。

设有两个整数 xxyy,交换第 kk 位的值。如果 xxyy 的第 kk 位的值相同,则操作无意义。因此只考虑第kk位不同的情形,假设交换前:

  • xk=0x_k = 0
  • yk=1y_k = 1

则交换后的乘积为:

     (x+2k)(y2k)=xy+2ky2kx22k=xy+2k(yx2k)\begin{align*} &\ \ \ \ \ (x + 2^k)(y - 2^k) \\ &= xy + 2^ky - 2^kx - 2^{2k} \\ & = xy + 2^k(y-x-2^k) \end{align*}

对比交换前的乘积 xyxy,需满足:

xy>xy+2k(yx2k)0>2k(yx2k)x>y2k\begin{align*} xy &\gt xy + 2^k(y-x-2^k) \\ 0 &\gt 2^k(y-x-2^k) \\ x &\gt y-2^k \end{align*}

总结一下:只要数组中存在两个整数 xxyy,且存在 k[0,P1]k∈[0,P-1],满足 xk=0x_k = 0yk=1y_k = 1,且 x>y2kx \gt y-2^k,则通过交换xxyy 的 第 kk 位即可减小乘积。

反过来想,如果数组中不存在这样的 xxyy,则就达到了最小的乘积。

先考虑 [1,2P2][1, 2^P-2] 区间内的数字,我们可将这 2P22^P-2 个数字分成 2P112^{P-1}-1 对,每队数字 (x,y)(x,y) 均满足 x+y=2P1x+y = 2^P-1

注意,2P12^P-1 是个很特殊的数字,是由 PP11 组成的。

换言之,如果 x+y=2P1x+y = 2^P-1,则对于任意 k[0,P)k∈[0,P),均有xkykx_k\ne y_k。那么,若 (x,y)(x,y) 满足 x+y=2P1x+y = 2^P-1,则其最小非零乘积为 2P22^P-2。即:

  • x=2P2x = 2^P-2
  • y=1y = 1

将每一对 (x,y)(x,y) 都置为 (2P2,1)(2^P-2, 1),则此时我们共有 2P12^P-1 个数,分别为:

  • 2P1112^{P-1}-1 个 1
  • 2P112P22^{P-1}-1 个 2^P-2
  • 12P11 个 2^P-1

受限于「x>y2kx \gt y-2^k」 以及 「非零乘积」两个要求,此时无法再进行交换了。因此最终答案为: (2P2)2P112P1mod(1e9+7)(2^{P}-2)^{2^{P-1}-1}*2^{P-1}\bmod {(1e9+7)}

class Solution {
public:
    const int64_t MOD = 1e9+7;
    int64_t pow(int64_t e, int64_t p, int64_t mod = std::numeric_limits<int64_t>::max()) {
        if (p == 0) { return 1; }
        if (p == 1) { return e%mod; }
        int64_t m = pow(e, p/2, mod);
        return m*m%mod * ((p&1) ? e%mod : 1) % mod;
    }
    int minNonZeroProduct(int p) {
        int64_t anw = 1;
        (anw *= (pow(2, p) - 1)) %= MOD;
        (anw *= pow(pow(2, p) - 2, pow(2, p-1)-1, MOD)) %= MOD;
        return anw;
    }
};

5845. 你能穿过矩阵的最后一天

思路:二分,广度优先遍历

时间复杂度O(nlgn)O(n\lg n)nn 为格子总数

如果第 kk 天能从第一行走到最后一行,那么前k1k-1天也可以,因为之前k1k-1天的陆地更多。

如果第 kk 天不能从第一行走到最后一行,那么之后的每一天也不能,因为陆地在不断减少。

显然,满足二分的条件,上限为 rc1r*c-1,下限为 00

对于二分的每一个值 midmid,此时地图中仅 cells0cells_0cells1cells_1,... cellsmidcells_{mid} 处变为了水域。然后判断是否有从第一行到最后一行的路径即可,或者判断是否有从第一列到最后一列的淹水区域也可。

class Solution {
public:
    bool check(int r, int c, const vector<vector<int>> &cell, int n) {
        vector<vector<bool>> mark(r, vector<bool>(c, false));
        
        queue<pair<int, int>> q;
        
        for (int i = 0; i < n; i++) {
            int x = cell[i][0]-1;
            int y = cell[i][1]-1;
            if (y == 0) {
                q.push(make_pair(x,y));
            } else {
                mark[x][y] = true;
            }
        }
        
        while(!q.empty()) {
            auto f = q.front();
            q.pop();
            if (f.second == c-1) {
                return true;
            }
            
            int dx[] = {-1,  0,  1,  0, -1, -1, 1, 1};
            int dy[] = { 0, -1,  0,  1, -1,  1,-1, 1};
            
            for (int i = 0; i < 8; i++) {
                int nx = f.first + dx[i];
                int ny = f.second + dy[i];
                if (0 <= nx && nx < r && 0 <= ny && ny < c && mark[nx][ny]) {
                    mark[nx][ny] = false;
                    q.push(make_pair(nx, ny));
                }
            }
        }
        return false;
    }
    int latestDayToCross(int row, int col, vector<vector<int>>& cells) {
        int L = 0, R = cells.size()-1;
        while (L <= R) {
            int mid = (L+R)/2;
            if (check(row, col, cells, mid) == false) {
                L = mid+1;
            } else {
                R = mid-1;
            }
        }
        return L-1;
    }
};