2020年8月2日,LeetCode第200场周赛个人记录。本次周赛题目相对而言有一点简单,至少可以全部做出来,但是做题速度上依旧有很大的提升空间,4到题目共耗时1小时34分钟,错误提交3次。原本在结束前全部做完还沾沾自喜,没想到一看排名只有300名,果然算法之路永无止境。
因为LeetCode并没有放出原题,所以暂时不贴出题目链接,等过几天原题放出后再贴。
给你一个整数数组 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
其中 |x| 表示 x 的绝对值,返回 好三元组的数量 。
3 <= arr.length <= 100
0 <= arr[i] <= 1000
0 <= a, b, c <= 1000
作为第一题送分题,本题还是十分简单的,因为数据规模不大,最大只有100个,所以考虑暴力法是可行的,直接上代码。
class Solution {
public:
int countGoodTriplets(vector<int>& arr, int a, int b, int c) {
int sum = 0;
for (int i = 0; i < arr.size() - 2; ++i)
for (int j = i + 1; j < arr.size() - 1; ++j)
for (int k = j + 1; k < arr.size(); ++k)
{
if (abs(arr[i] - arr[j]) <= a && abs(arr[j] - arr[k]) <= b && abs(arr[i] - arr[k]) <= c)
++sum;
}
return sum;
}
};
给你一个由 不同 整数组成的整数数组 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
乍一看此题难度很大,因为k的数据可以达到10⁹,这意味着我们要进行这么多次的比较,但是仔细想一想,因为要保证一个数赢k次,而当k大于等于数组长度时,就意味着整个数组里最大的元素一定会被比较,并且中断前面所有数的连胜。即当k大于等于数组长度时,可以直接返回数组中最大值。这样我们要进行的比较规模大幅度减小为10⁵,如此小的规模,可以直接暴力解决。
class Solution {
public:
int getWinner(vector<int>& arr, int k) {
int size = arr.size();
if (k > size - 1) //直接返回数组中最大的元素
{
int maxVal = 0;
for (auto x: arr)
maxVal = max(maxVal, x);
return maxVal;
}
int times = 0;
for (int i = 1; i < size; ++i) //暴力比较
{
if (arr[0] > arr[i])
++times;
else
{
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
times = 1;
}
if (times == k)
return arr[0];
}
/*
如果遍历完一遍后任然没有元素连胜达到k次,那么此时数组中最大的元素一定已经被遍历过进行比较并且在首位,
我们也知道最大的元素最后一定能连胜k次,所以直接返回arr[0]
*/
return arr[0];
}
};
给你一个 n x n 的二进制网格 grid,每一次操作中,你可以选择网格的 相邻两行 进行交换。
一个符合要求的网格需要满足主对角线以上的格子全部都是 0 。
请你返回使网格满足要求的最少操作次数,如果无法使网格符合要求,请你返回 -1 。
主对角线指的是从 (1, 1) 到 (n, n) 的这些格子。
n == grid.length
n == grid[i].length
1 <= n <= 200
grid[i][j] 要么是 0 要么是 1 。
暴力,继续暴力,果然暴力解万法,说起来本次周赛所有的题目都是用暴力法解决,难道paypal就喜欢暴力?这道题目看要我们求最小操作次数,很多人可能和我一样想用动规或者贪心解决,但是实际上如果我们画几个矩阵操作一遍,就会发现只要能满足要求,那么不管怎么操作,操作次数都是一样的。所以我们直接一排一排的排好,交换,最后得出的交换次数就是最少的操作次数。每一排我们需要倒着计算连续的0的个数,下标为i的行需要的连续0的个数为size - 1 - i。
class Solution {
public:
int minSwaps(vector<vector<int>>& grid) {
int size = grid.size();
int sum = 0;
for (int i = 0; i < size - 1; ++i)
{
int j;
for (j = i; j < size; ++j)
if (isValid(grid[j], size - 1 - i)) //isValid是用来判断第j行是否有连续的size - 1 - i个0来交换到第i行
break;
if (j == size) //找不到能换到第i行的那一行,所以返回-1
return -1;
for (; j > i; --j) //交换相邻的两行
{
swap(grid[j], grid[j - 1]);
++sum;
}
}
return sum;
}
bool isValid(vector<int> &a, int target)
{
for (int i = a.size() - 1; i >= 0; --i) //倒序计算连续的0的个数
{
if (a[i] == 1)
break;
--target;
}
return target <= 0;
}
};
你有两个 有序 且数组内元素互不相同的数组 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 都是严格递增的数组。
让我们把暴力贯彻到底,本题因为两个数组都是递增的数组,所以不会出现跳来跳去成环的情况。我们把都存在的值称作分叉点,我们要关注的其实是两个分叉点之间走nums1还是走nums2,这个很好办,我们都走一遍算一下那个值更大,我们就走哪一条路。具体思路是,先遍历两个数组,用map存储每个值出现的次数,我们可以把开头和结尾也视为分叉点,每当我们遇到分叉点时,我们将分叉点的值加上去,然后分别计算nums1和nums2到下一个分叉点的和,将大的数加到总和上,这样我们就遇到了下一个分叉点,重复此过程,就能得到最终结果。要注意的是,计算和的时候数字可能会很大超过int可表示范围,我们使用long甚至是long long来计算和。
class Solution {
public:
int maxSum(vector<int>& nums1, vector<int>& nums2) {
long long sum = 0; //防止整形溢出
const int MOD = 1e9 + 7; //取模的常数
map<int, int> myMap;
for (auto x: nums1) //两个for遍历数组计算每个值出现的次数
myMap[x]++;
for (auto x: nums2)
{
myMap[x]++;
if (myMap[x] == 2) //将出现两次的数提前加到sum中,方便统一处理
{
sum += x;
sum %= MOD;
}
}
long long sum1 = 0, sum2 = 0;
int index1 = 0, index2 = 0;
while (index1 < nums1.size() || index2 < nums2.size()) //当两个数组都遍历到尾时停止
{
sum1 = sum2 = 0;
for (; index1 < nums1.size() && myMap[nums1[index1]] != 2; ++index1) //计算nums1到下一个分叉点的和
sum1 += nums1[index1];
for (; index2 < nums2.size() && myMap[nums2[index2]] != 2; ++index2) //计算nums2到下一个分叉点的和
sum2 += nums2[index2];
sum += max(sum1, sum2);
sum %= MOD;
++index1; //此时index1和index2在分叉点的位置上,为了方便统一处理,我们直接跳过分叉点
++index2;
}
return sum;
}
};
本次周赛虽然比较简单,而且题目都是用暴力法解出来,但是也是我第一次在周赛中完整的做出4道题目,虽然排名不怎么样,但也是一个不小的进步。创作不易,还请多多支持。