LeetCode第 200 场周赛详解

LeetCode第 200 场周赛详解

1.统计好三元组[原题链接]

题意:

给你一个整数数组 arr ,以及 abc 三个整数。请你统计其中好三元组的数量。

如果三元组 (arr[i], arr[j], arr[k]) 满足下列全部条件,则认为它是一个 好三元组 。
0 <= i < j < k < arr.length
|arr[i] - arr[j]| <= a
|arr[j] - arr[k]| <= b
|arr[i] - arr[k]| <= c

数据范围:

3 <= arr.length <= 100
0 <= arr[i] <= 1000
0 <= a, b, c <= 1000

思路:

简单的枚举即可

代码:
class Solution {
public:
    int countGoodTriplets(vector<int>& arr, int a, int b, int c) {
        int n = arr.size();
        int ret = 0;
        for (int i = 0; i < n; ++i)
            for (int j = i + 1; j < n; ++j)
                for (int k = j + 1; k < n; ++k) {
                    if (abs(arr[i] - arr[j]) <= a && 
                    	abs(arr[j] - arr[k]) <= b && 
                    	abs(arr[i] - arr[k]) <= c)
                        ++ret;    
                }
        
        return ret;
    }
};

2.找出数组游戏的赢家[原题链接]

题意:

给你一个由 不同 整数组成的整数数组 arr 和一个整数 k

每回合游戏都在数组的前两个元素(即 arr[0]arr[1] )之间进行。比较 arr[0]arr[1] 的大小,较大的整数将会取得这一回合的胜利并保留在位置 0 ,较小的整数移至数组的末尾。当一个整数赢得 k 个连续回合时,游戏结束,该整数就是比赛的赢家 。

返回赢得比赛的整数。

题目数据 保证 游戏存在赢家。

数据范围:

2 <= arr.length <= 10^5
1 <= arr[i] <= 10^6
arr所含的整数各不相同
1 <= k <= 10^9

思路:

首先按照模拟思路来想,如果比赛进行的次数足够多,使得数组中每个元素都被比较了的话,那么最终留下的整数必定是最大值,而且最大值将一直赢下接下来所有的比赛。明白这一点就好做了,直接模拟思路,从前往后去比较,并记录目前该元素赢下比赛的次数,如果所有数组元素都比较过了还没得出赢家,那么赢家就是最大值。

代码:
class Solution {
public:
    int getWinner(vector<int>& arr, int k) {
        int ret = 0, n = arr.size();
        int cur = arr[0], cost = 0;
        for (int i = 1; i < n; ++i) {
            if (cur > arr[i]) ++cost;
            else {
                cost = 1;
                cur = arr[i];
            }
            if (cost == k) return cur;
        }
        
        return cur;
    }
};

3.排布二进制网格的最少交换次数[原题链接]

题意:

给你一个 n x n 的二进制网格 grid,每一次操作中,你可以选择网格的相邻两行进行交换。一个符合要求的网格需要满足主对角线以上的格子全部都是 0

请你返回使网格满足要求的最少操作次数,如果无法使网格符合要求,请你返回 -1

主对角线指的是从 (1, 1)(n, n) 的这些格子。
示例
LeetCode第 200 场周赛详解_第1张图片

数据范围:

n == grid.length
n == grid[i].length
1 <= n <= 200
grid[i][j] == 0 OR 1

思路:

可以看到每一行末尾连续要求的 0 的个数是递减的,比如对于一个 3 × 3 的网格来说,第一行末尾连续的 0 的个数需要 >= 2 ,第二行末尾连续的 0 的个数需要 >= 1 ,那么放在第一行能满足的某一行当然放在第二行也满足条件。所以我们可以从上往下依次贪心地去取离当前第 k 行最近的且可以满足当前这行的条件的 grid[i], i >= k ,即末尾连续 0 的个数 >= n - k - 1,然后将其向上一直交换至第 k 行。

代码:
class Solution {
public:
    int minSwaps(vector<vector<int>>& grid) {
        int n = grid.size();
        
        vector<int> a(n);
        ** a[i] 表示第 i 行末尾连续 0 的个数
        for (int i = 0; i < n; ++i) {
            int j = n - 1;
            for ( ; j >= 0; --j) if (grid[i][j]) break;
            a[i] = n - j - 1;
        }
        
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            int j = i;
            ** d 表示 第 i 行需要末尾连续 0 的个数
            int d = n - i - 1;
            for ( ; j < n; ++j) if (a[j] >= d) break;
            if (j >= n) return -1;
            ** 从 j 到 i 向上交换
            for (int k = j; k > i; --k, ++ans) swap(a[k], a[k - 1]);
        }
        
        return ans;
    }
};

4.最大得分[原题链接]

题意:

你有两个有序且数组内元素互不相同的数组 nums1nums2

一条合法路径定义如下:
选择数组 nums1 或者 nums2 开始遍历(从下标 0 处开始)。从左到右遍历当前数组。如果你遇到了 nums1nums2 中都存在的值,那么你可以切换路径到另一个数组对应数字处继续遍历(但在合法路径中重复数字只会被统计一次)。

得分定义为合法路径中不同数字的和。请你返回所有可能合法路径中的最大得分。

由于答案可能很大,请你将它对 10^9 + 7 取余后返回。

示例
LeetCode第 200 场周赛详解_第2张图片

数据范围:

1 <= nums1.length <= 10^5
1 <= nums2.length <= 10^5
1 <= nums1[i], nums2[i] <= 10^7
nums1 和 nums2 都是严格递增的数组

思路:

我们可以用 双指针+动态规划 来解这道题。
f1[i] 表示从数组 nums1 下标 i 出发可以获得的最大分数。
f2[i] 表示从数组 nums2 下标 i 出发可以获得的最大分数。
则最终返回结果就是 max(f1[0], f2[0]) % (1e9 + 7);
这里我们需要从后往前递推,因为路径是从前往后走的,所以要对 f1[i], f2[i] 进行状态转移我们需要知道 f1[i + 1], f2[i + 1],利用双指针是为了保证切换至另外一个数组的时候,可以更新状态。比如:nums1[i] == nums2[j]f1[i], f2[j] 可以通过切换数组来更新状态,这时需要保证 f1[i], f2[j] 已经计算过不在这点切换数组的次优路径。
(这道题的状态转移只跟上一个状态有关,其实是可以进行状态压缩的,有兴趣的同学可以试一下。)

代码:
typedef long long LL;
class Solution {
public:
    const int MOD = 1e9 + 7;
    int maxSum(vector<int>& nums1, vector<int>& nums2) {
        int n1 = nums1.size(), n2 = nums2.size();
        
        vector<LL> f1(n1 + 1, 0), f2(n2 + 1, 0);
        int k1 = n1 - 1, k2 = n2 - 1;
        for ( ; k1 >= 0 && k2 >= 0; ) {
            f1[k1] = f1[k1 + 1] + (LL)nums1[k1];
            f2[k2] = f2[k2 + 1] + (LL)nums2[k2];
            if (nums1[k1] == nums2[k2]) {
                f1[k1] = f2[k2] = max(f1[k1], f2[k2]);
                --k1;
                --k2;
            } else if (nums1[k1] > nums2[k2]) {
                --k1;
            } else {
                --k2;
            }
        }
        
        while (k1 >= 0) {
            f1[k1] = f1[k1 + 1] + nums1[k1];
            k1--;
        }
        
        while (k2 >= 0) {
            f2[k2] = f2[k2 + 1] + nums2[k2];
            k2--;
        }
           
        return max(f1[0], f2[0]) % MOD;
    }
};

战绩:

在这里插入图片描述
能直接睡到11:20我也是醉了,冒着掉分的危险打了这场比赛,最后一题12:00调出来没赶上,没仔细看题,重复数字统计了两次/(ㄒoㄒ)/~~
codeforce的比赛暂时不写了,翻译题目好累好累的,主要自己也写不了多少题,基本都是官方的tutorial的搬运工,卑微。

你可能感兴趣的:(算法竞赛)