天天看点

Java实现LeetCode第200场周赛(题号5475-5478)

看起来挺简单,但是上午有事情我就没做,一看就会,一做就废选手在此

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

Java实现LeetCode第200场周赛(题号5475-5478)

这不是再告诉我暴力走天下吗,哈哈哈

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

解释:一起看一下本场游戏每回合的情况:

Java实现LeetCode第200场周赛(题号5475-5478)

因此将进行 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:

Java实现LeetCode第200场周赛(题号5475-5478)

输入:grid = [[0,0,1],[1,1,0],[1,0,0]]

输出:3

示例 2:

Java实现LeetCode第200场周赛(题号5475-5478)

输入:grid = [[0,1,1,0],[0,1,1,0],[0,1,1,0],[0,1,1,0]]

输出:-1

解释:所有行都是一样的,交换相邻行无法使网格符合要求。

示例 3:

Java实现LeetCode第200场周赛(题号5475-5478)

输入: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:

Java实现LeetCode第200场周赛(题号5475-5478)

输入: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);
    }
 
}