给你一个整数数组 arr
,以及 a
、b
、c
三个整数。请你统计其中好三元组的数量。
如果三元组 (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;
}
};
给你一个由 不同 整数组成的整数数组 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;
}
};
给你一个 n x n
的二进制网格 grid
,每一次操作中,你可以选择网格的相邻两行进行交换。一个符合要求的网格需要满足主对角线以上的格子全部都是 0
。
请你返回使网格满足要求的最少操作次数,如果无法使网格符合要求,请你返回 -1
。
主对角线指的是从 (1, 1)
到 (n, n)
的这些格子。
示例
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;
}
};
你有两个有序且数组内元素互不相同的数组 nums1
和 nums2
。
一条合法路径定义如下:
选择数组 nums1
或者 nums2
开始遍历(从下标 0
处开始)。从左到右遍历当前数组。如果你遇到了 nums1
和 nums2
中都存在的值,那么你可以切换路径到另一个数组对应数字处继续遍历(但在合法路径中重复数字只会被统计一次)。
得分定义为合法路径中不同数字的和。请你返回所有可能合法路径中的最大得分。
由于答案可能很大,请你将它对 10^9 + 7
取余后返回。
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的搬运工,卑微。