看起来挺简单,但是上午有事情我就没做,一看就会,一做就废选手在此
5475. 统计好三元组
5476. 找出数组游戏的赢家
5477. 排布二进制网格的最少交换次数
5478. 最大得分
5475. 统计好三元组
给你一个整数数组 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 的绝对值。
返回 好三元组的数量 。
示例 1:
输入:arr = [3,0,1,1,9,7], a = 7, b = 2, c = 3
输出:4
解释:一共有 4 个好三元组:[(3,0,1), (3,0,1), (3,1,1), (0,1,1)] 。
示例 2:
输入:arr = [1,1,2,2,3], a = 0, b = 0, c = 1
输出:0
解释:不存在满足所有条件的三元组。
提示:
3 <= arr.length <= 100
0 <= arr[i] <= 1000
0 <= a, b, c <= 1000
这不是再告诉我暴力走天下吗,哈哈哈
class Solution {
public int countGoodTriplets(int[] arr, int a, int b, int c) {
int len = arr.length, cnt = 0;
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len; j++) {
for (int z = j + 1; z < len; z++) {
if (Math.abs(arr[i] - arr[j]) <= a && Math.abs(arr[j] - arr[z]) <= b
&& Math.abs(arr[i] - arr[z]) <= c){
cnt++;
}
}
}
}
return cnt;
}
}
5476. 找出数组游戏的赢家
给你一个由 不同 整数组成的整数数组 arr 和一个整数 k 。
每回合游戏都在数组的前两个元素(即 arr[0] 和 arr[1] )之间进行。比较 arr[0] 与 arr[1] 的大小,较大的整数将会取得这一回合的胜利并保留在位置 0 ,较小的整数移至数组的末尾。当一个整数赢得 k 个连续回合时,游戏结束,该整数就是比赛的 赢家 。
返回赢得比赛的整数。
题目数据 保证 游戏存在赢家。
示例 1:
输入:arr = [2,1,3,5,4,6,7], k = 2
输出:5
解释:一起看一下本场游戏每回合的情况:
因此将进行 4 回合比赛,其中 5 是赢家,因为它连胜 2 回合。
示例 2:
输入:arr = [3,2,1], k = 10
输出:3
解释:3 将会在前 10 个回合中连续获胜。
示例 3:
输入:arr = [1,9,8,2,3,7,6,4,5], k = 7
输出:9
示例 4:
输入:arr = [1,11,22,33,44,55,66,77,88,99], k = 1000000000
输出:99
提示:
2 <= arr.length <= 10^5
1 <= arr[i] <= 10^6
arr 所含的整数 各不相同 。
1 <= k <= 10^9
class Solution {
public int getWinner(int[] arr, int k) {
int n = arr.length;
//如果k大于n就找这个数组中最大的那个数就行了
if (k>=n){
return Arrays.stream(arr).max().getAsInt();
}
//否则就直接模拟就可以了
//这里可能不理解为什么循环到最后就可以了,万一他不到k怎么办
//这是我们要想,如果能替换为最大的,那么他肯定是最大的那个,既然是最大的,无论循环多少次都是最大的
int time = 0;
int val = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i]>val){
val = arr[i];
time = 0;
}
time++;
if (time == k){
break;
}
}
return val;
}
}
5477. 排布二进制网格的最少交换次数
给你一个 n x n 的二进制网格 grid,每一次操作中,你可以选择网格的 相邻两行 进行交换。
一个符合要求的网格需要满足主对角线以上的格子全部都是 0 。
请你返回使网格满足要求的最少操作次数,如果无法使网格符合要求,请你返回 -1 。
主对角线指的是从 (1, 1) 到 (n, n) 的这些格子。
示例 1:
输入:grid = [[0,0,1],[1,1,0],[1,0,0]]
输出:3
示例 2:
输入:grid = [[0,1,1,0],[0,1,1,0],[0,1,1,0],[0,1,1,0]]
输出:-1
解释:所有行都是一样的,交换相邻行无法使网格符合要求。
示例 3:
输入:grid = [[1,0,0],[1,1,0],[1,1,1]]
输出:0
提示:
n == grid.length
n == grid[i].length
1 <= n <= 200
grid[i][j] 要么是 0 要么是 1 。
class Solution {
/*
做法都是差不多的:
看每行的最后有几个0,
交换求,第i行的末尾0的数量为n-i-1,如果小于了,
就直接返回-1就行了,肯定不符合条件的
*/
public int minSwaps(int[][] grid) {
int n = grid.length;
int res = 0;
int sum;
int[] cnt = new int[n];
//计算末尾0的数量
for(int i=0;i<n;i++){
sum=0;
for(int j=n-1;j>=0;j--){
if(grid[i][j]==0) sum++;
else break;
}
cnt[i]=sum;
}
for(int i=0;i<n;i++){
if(cnt[i]<n-i-1){
for(int j=i+1;j<n;j++){
//只要满足条件就可以交换一次,停止了
//这里因为cnt[i]i越小,cnt[i]会越大
if(cnt[j]>=n-i-1){
res+=swap(cnt,i,j);
break;
}
}
}
}
//根据上面的图片可以找到第i行末尾0的数量最少为多少
for(int i=0;i<n;i++){
if(cnt[i]<n-1-i) return -1;
}
return res;
}
private int swap(int[] num,int i,int j){
int count = 0;
while(j>i){
int temp = num[j-1];
num[j-1] = num[j];
num[j]=temp;
j--;
count++;
}
return count;
}
}
5478. 最大得分
你有两个 有序 且数组内元素互不相同的数组 nums1 和 nums2 。
一条 合法路径 定义如下:
选择数组 nums1 或者 nums2 开始遍历(从下标 0 处开始)。
从左到右遍历当前数组。
如果你遇到了 nums1 和 nums2 中都存在的值,那么你可以切换路径到另一个数组对应数字处继续遍历(但在合法路径中重复数字只会被统计一次)。
得分定义为合法路径中不同数字的和。
请你返回所有可能合法路径中的最大得分。
由于答案可能很大,请你将它对 10^9 + 7 取余后返回。
示例 1:
输入:nums1 = [2,4,5,8,10], nums2 = [4,6,8,9]
输出:30
解释:合法路径包括:
[2,4,5,8,10], [2,4,5,8,9], [2,4,6,8,9], [2,4,6,8,10],(从 nums1 开始遍历)
[4,6,8,9], [4,5,8,10], [4,5,8,9], [4,6,8,10] (从 nums2 开始遍历)
最大得分为上图中的绿色路径 [2,4,6,8,10] 。
示例 2:
输入:nums1 = [1,3,5,7,9], nums2 = [3,5,100]
输出:109
解释:最大得分由路径 [1,3,5,100] 得到。
示例 3:
输入:nums1 = [1,2,3,4,5], nums2 = [6,7,8,9,10]
输出:40
解释:nums1 和 nums2 之间无相同数字。
最大得分由路径 [6,7,8,9,10] 得到。
示例 4:
输入:nums1 = [1,4,5,8,9,11,19], nums2 = [2,3,4,11,12]
输出:61
提示:
1 <= nums1.length <= 10^5
1 <= nums2.length <= 10^5
1 <= nums1[i], nums2[i] <= 10^7
nums1 和 nums2 都是严格递增的数组。
class Solution {
/*
做题要先发现那些小细节:
他只说了重复数字只会记录一次,但是我们还是可以走的
有序
思路:
求两个队列相等时可以切换的最大值
双指针模拟
如果a队列的那个值>b队列的那个值,那么b队列的最大值只能+b队列的那个值了,
因为本身a>b了,后面会越差越大的,因为他是有序的,把b往后走一位才可能相等
反之a<b的话,就反着想,
如果相等了,就用两个队列的最大的值替换原来的值,别忘了加上当前这个值,
题目只给出了,不会重复计算相同的值,但并不意味我们不可以走,
我们把之前的两个队列的值替换了,下面还用这种方法找
(PS:在这个相等获得完最大值以后,在加的话如果当前队列的值是另一个队列之前的值,
可能有的人会怀疑这么写不对,他明明是另一个队列的最大值,并不是当前队列的,
这时你就可以想一下,我走过去在走回来不就是这个队列的了,反正重复的只)
*/
public int maxSum(int[] nums1, int[] nums2) {
int MOD =1000000007;
//两个数列的最大值
long ans1 = 0, ans2 = 0;
//两个数列的下标
int i = 0, j = 0;
//如果有一个到头了,就不能再用了
while (i < nums1.length && j < nums2.length) {
//如果num2[j]大了,就不能切换数组了(毕竟是有序数组,后面会越差越多)
if (nums1[i] < nums2[j]) {
ans1 += nums1[i];
i++;
//反之,num[i]大了,也一样
} else if (nums1[i] > nums2[j]) {
ans2 += nums2[j];
j++;
} else {
//如果两个值一样了,就选择最大的那个把两个队列的值替换掉,还要加上当前的值
ans1 = Math.max(ans1, ans2) + nums1[i];
ans2 = ans1;
i++;
j++;
}
}
//把第一个序列的或者第二个序列的未完成的完成了
while (i < nums1.length) {
ans1 += nums1[i];
i++;
}
while (j < nums2.length) {
ans2 += nums2[j];
j++;
}
return (int) (Math.max(ans1, ans2) % MOD);
}
}