LeetCode852. 山脉数组的峰顶索引 / 374. 猜数字大小 / 278. 第一个错误的版本 / 第 54 场双周赛 / 第 245 场周赛

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode852. 山脉数组的峰顶索引 / 374. 猜数字大小 / 278. 第一个错误的版本 / 第 54 场双周赛 / 第 245 场周赛相关的知识,希望对你有一定的参考价值。

852. 山脉数组的峰顶索引

2021.6.15每日一题

题目描述

符合下列属性的数组 arr 称为 山脉数组 :
arr.length >= 3
存在 i(0 < i < arr.length - 1)使得:
arr[0] < arr[1] < ... arr[i-1] < arr[i]
arr[i] > arr[i+1] > ... > arr[arr.length - 1]
给你由整数组成的山脉数组 arr ,返回任何满足 arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 的下标 i 。


示例 1:

输入:arr = [0,1,0]
输出:1
示例 2:

输入:arr = [0,2,1,0]
输出:1
示例 3:

输入:arr = [0,10,5,2]
输出:1
示例 4:

输入:arr = [3,4,5,1]
输出:2
示例 5:

输入:arr = [24,69,100,99,79,78,67,36,26,19]
输出:2

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/peak-index-in-a-mountain-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

已经连续第三天是一道简单的二分查找了,咋回事,说好的动规呢???
二分第一种写法,(向上取整)

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        //怎么突然连续三天变成二分查找了
        int l = arr.length;
        int left = 1;
        int right = l - 1;
        while(left < right){
            int mid = (right - left + 1) / 2 + left;
            if(arr[mid] < arr[mid - 1]){
                right = mid - 1;
            }else{
                left = mid;
            }
        }
        return left;
    }
}

374. 猜数字大小

2021.6.14每日一题

题目描述

猜数字游戏的规则如下:

每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):

-1:我选出的数字比你猜的数字小 pick < num
1:我选出的数字比你猜的数字大 pick > num
0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num
返回我选出的数字。


示例 1:

输入:n = 10, pick = 6
输出:6
示例 2:

输入:n = 1, pick = 1
输出:1
示例 3:

输入:n = 2, pick = 1
输出:1
示例 4:

输入:n = 2, pick = 2
输出:2

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/guess-number-higher-or-lower
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

二分第二种写法

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        int left = 1;
        int right = n;
        while(left <= right){
            int mid = (right - left) / 2 + left; 
            if(guess(mid) == 0){
                return mid;
            }else if(guess(mid) == 1)
                left = mid + 1;
            else
                right = mid - 1;
        }
        return left;
    }
}

278. 第一个错误的版本

2021.6.13每日一题

题目描述

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

示例:

给定 n = 5,并且 version = 4 是第一个错误的版本。

调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true

所以,4 是第一个错误的版本。 

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/first-bad-version
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

第一个二分查找的写法(向下取整)

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int left = 1;
        int right = n;
        while(left < right){
            int mid = left + (right - left) / 2;
            boolean x = isBadVersion(mid);
            if(!x)
                left = mid + 1;
            if(x){
                right = mid;
            }
                
        }
        return left;
    }
}

第 54 场双周赛

1893. 检查是否区域内所有整数都被覆盖

t题目描述

给你一个二维整数数组 ranges 和两个整数 left 和 right 。每个 ranges[i] = [starti, endi] 表示一个从 starti 到 endi 的 闭区间 。

如果闭区间 [left, right] 内每个整数都被 ranges 中 至少一个 区间覆盖,那么请你返回 true ,否则返回 false 。

已知区间 ranges[i] = [starti, endi] ,如果整数 x 满足 starti <= x <= endi ,那么我们称整数x 被覆盖了。

 

示例 1:

输入:ranges = [[1,2],[3,4],[5,6]], left = 2, right = 5
输出:true
解释:2 到 5 的每个整数都被覆盖了:
- 2 被第一个区间覆盖。
- 3 和 4 被第二个区间覆盖。
- 5 被第三个区间覆盖。
示例 2:

输入:ranges = [[1,10],[10,20]], left = 21, right = 21
输出:false
解释:21 没有被任何一个区间覆盖。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/check-if-all-the-integers-in-a-range-are-covered
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

当时想到的就是排序,然后遍历,所有区间,找对应的值
但是刚开始我加了这么一句话,导致直接提交了三次都过不了,哭死!唉
if(left < ranges[0][0] || right > ranges[l - 1][1]) return false;
最后过的代码:

class Solution {
    public boolean isCovered(int[][] ranges, int left, int right) {
        Arrays.sort(ranges, new Comparator<int[]>(){
            public int compare(int[] x, int[] y){
                return x[1] == y[1] ? x[0] - y[0] : x[1] - y[1];
            }
        });
        //或者用正则表达式
        //Arrays.sort(ranges, (x, y) ->{
        //    return x[0] == y[0] ? x[1] - y[1] : x[0] - y[0];
        //});
        
        int index = 0;
        int l = ranges.length;

        while(left <= right){
            if(left >= ranges[index][0] && left <= ranges[index][1])
                left++;
            else
                index++;
            if(index >= l)
                break;

        }
        if(left > right)
            return true;
        else
            return false;
    }
}

说实话,题解的差分数组,没大看懂…

1894. 找到需要补充粉笔的学生编号

题目描述

一个班级里有 n 个学生,编号为 0 到 n - 1 。每个学生会依次回答问题,编号为 0 的学生先回答,然后是编号为 1 的学生,以此类推,直到编号为 n - 1 的学生,然后老师会重复这个过程,重新从编号为 0 的学生开始回答问题。

给你一个长度为 n 且下标从 0 开始的整数数组 chalk 和一个整数 k 。一开始粉笔盒里总共有 k 支粉笔。当编号为 i 的学生回答问题时,他会消耗 chalk[i] 支粉笔。如果剩余粉笔数量 严格小于 chalk[i] ,那么学生 i 需要 补充 粉笔。

请你返回需要 补充 粉笔的学生 编号 。


示例 1:

输入:chalk = [5,1,5], k = 22
输出:0
解释:学生消耗粉笔情况如下:
- 编号为 0 的学生使用 5 支粉笔,然后 k = 17 。
- 编号为 1 的学生使用 1 支粉笔,然后 k = 16 。
- 编号为 2 的学生使用 5 支粉笔,然后 k = 11 。
- 编号为 0 的学生使用 5 支粉笔,然后 k = 6 。
- 编号为 1 的学生使用 1 支粉笔,然后 k = 5 。
- 编号为 2 的学生使用 5 支粉笔,然后 k = 0 。
编号为 0 的学生没有足够的粉笔,所以他需要补充粉笔。
示例 2:

输入:chalk = [3,4,1,2], k = 25
输出:1
解释:学生消耗粉笔情况如下:
- 编号为 0 的学生使用 3 支粉笔,然后 k = 22 。
- 编号为 1 的学生使用 4 支粉笔,然后 k = 18 。
- 编号为 2 的学生使用 1 支粉笔,然后 k = 17 。
- 编号为 3 的学生使用 2 支粉笔,然后 k = 15 。
- 编号为 0 的学生使用 3 支粉笔,然后 k = 12 。
- 编号为 1 的学生使用 4 支粉笔,然后 k = 8 。
- 编号为 2 的学生使用 1 支粉笔,然后 k = 7 。
- 编号为 3 的学生使用 2 支粉笔,然后 k = 5 。
- 编号为 0 的学生使用 3 支粉笔,然后 k = 2 。
编号为 1 的学生没有足够的粉笔,所以他需要补充粉笔。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-the-student-that-will-replace-the-chalk
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

这个题感觉比第一个题还简单,需要注意的就是用long防止溢出

class Solution {
    public int chalkReplacer(int[] chalk, int k) {
        int l = chalk.length;
        int index = 0;
        long sum = 0;
        for(int i = 0; i < l; i++){
            sum += chalk[i];
        }
        k = (int)((long)k % sum);
        while(k >= chalk[index]){
            k -= chalk[index];
            index = index + 1;
        }
        return index;
    }
}

1895. 最大的幻方

题目描述

一个 k x k 的 幻方 指的是一个 k x k 填满整数的方格阵,且每一行、每一列以及两条对角线的和 全部相等 。幻方中的整数 不需要互不相同 。显然,每个 1 x 1 的方格都是一个幻方。

给你一个 m x n 的整数矩阵 grid ,请你返回矩阵中 最大幻方 的 尺寸 (即边长 k)。


示例 1:

在这里插入图片描述

输入:grid = [[7,1,4,5,6],[2,5,1,6,4],[1,5,4,3,2],[1,2,7,3,4]]
输出:3
解释:最大幻方尺寸为 3 。
每一行,每一列以及两条对角线的和都等于 12 。
- 每一行的和:5+1+6 = 5+4+3 = 2+7+3 = 12
- 每一列的和:5+5+2 = 1+4+7 = 6+3+3 = 12
- 对角线的和:5+4+3 = 6+4+2 = 12

示例 2:

在这里插入图片描述

输入:grid = [[5,1,3,1],[9,3,3,1],[1,3,3,8]]
输出:2

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/largest-magic-square
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

做了几次周赛了,我发现第三道题很喜欢出这种矩阵题…好像每次都有一道矩阵题
然后就是有思路,但是写不对…
我看了下数据范围,本来想处理每一行每一列的前缀和来着,后面觉得写的太麻烦,看了下数据范围,觉得暴力也能过,直接暴力吧,但是代码还是一直有问题,debug一下,看看问题出在哪里

当时代码:

class Solution {
    int[][] grid;
    int m;
    int n;
    public int largestMagicSquare(int[][] grid) {
        //想了一会,觉得还不如之间遍历了
        this.grid = grid;
        int max = 1;
        int len = m < n ? m : n;
        //int[][] col = new int[m + 1][n + 1];
        //int[][] row = new int[m + 1][n + 1];
        //for(int i )


        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                for(int k = max; k <= len; k++){
                    if(k == 1)
                        continue;
                    //这里应该写成>
                    if(i + k >= m || j + k >= n)
                        break;
                    if(judge(i, j, k))
                        max = Math.max(k, max);              
                }
            }
        }
        return max;
    }
    public boolean judge(int i, int j, int k){
        int value = 0;
        //第i行的和
        for(int y = j; y < j + k; y++){
            value += grid[i][y];
        }
        
        //判断行和
        for(int x = i + 1; x < i + k; x++){
            int cur = 0;
            for(int y = j; y < j + k; y++){
                cur += grid[x][y];
            }
            if(cur != value)
                return false;
        }
     
        for(int x = j; x < j + k; x++){
            int cur = 0;
            for(int y = i; y < i + k; y++){
                cur += grid[y][x];
            }
            if(cur != value)
                return false;
        }
            
        //对角线
        int cox = 0;
        for(int x = 0; x < k; x++){
            cox += grid[i + x][j + x];
        }
        if(cox != value)
            return false;
  
        cox = 0;
        for(int x = 0; x < k; x++){
        	//这里是i+k-1-x
            cox += grid[i + k - x][j + x];
        }
        if(cox != value)
            return false;
   
        return true;
        
    }
}

debug了一下,立马发现了问题,然后提交立马AC了…题解里也就是多处理了个前缀和…
说实话,挺难受的,每次都和做出第三道题插肩而过
改了以后的代码:

class Solution {
    int[][] grid;

    public int largestMagicSquare(int[][] grid) {
        //想了一会,觉得还不如之间遍历了
        this.grid = grid;
        int m = grid.length;
        int n = grid[0].length;
        int max = 1;
        int len = m < n ? m : n;
        //int[][] col = new int[m + 1][n + 1];
        //int[][] row = new int[m + 1][n + 1];
        //for(int i )


        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                for(int k = max; k <= len; k++){
                    if(k == 1)
                        continue;
                    if(i + k > m || j + k > n)
                        break;
                    if(judge(i, j, k))
                        max = Math.max(k, max);
                }
            }
        }
        return max;
    }
    public boolean judge(int i, int j, int k){
        int value = 0;
        //第i行的和
        for(int y = j; y < j + k; y++){
            value += grid[i][y];
        }
        
        //判断行和
        for(int x = i + 1; x < i + k; x++){
            int cur = 0;
            for(int y = j; y < j + k; y++){
                cur += grid[x][y];
            }
            if(cur != value)
                return false;
        }
       
        for(int x = j; x < j + k; x++){
            int cur = 0;
            for(int y = i; y < i + k; y++){
                cur += grid[y][x];
            }
            if(cur != value)
                return false;
        }   
        
        //对角线
        int cox = 0;
        for(int x = 0; x < k; x++){
            cox += grid[i + x][j + x];
        }
        if(cox != value)
            return false;
       
       
        cox = 0;
        for(int x = 0; x < k; x++){
            cox += grid[i + k - 1 - x][j + x];
        }
        if(cox != value)
            return false;
   
        return true;
        
    }
}

1896. 反转表达式值的最少操作次数

题目描述

给你一个 有效的 布尔表达式,用字符串 expression 表示。这个字符串包含字符 '1','0','&'(按位 与 运算),'|'(按位 或 运算),'(' 和 ')' 。

比方说,"()1|1" 和 "(1)&()" 不是有效 布尔表达式。而 "1", "(((1))|(0))" 和 "1|(0&(1))" 是 有效 布尔表达式。
你的目标是将布尔表达式的 值 反转 (也就是将 0 变为 1 ,或者将 1 变为 0),请你返回达成目标需要的 最少操作 次数。

比方说,如果表达式 expression = "1|1|(0&0)&1" ,它的 值 为 1|1|(0&0)&1 = 1|1|0&1 = 1|0&1 = 1&1 = 1 。我们想要执行操作将 新的 表达式的值变成 0 。
可执行的 操作 如下:

将一个 '1' 变成一个 '0' 。
将一个 '0' 变成一个 '1' 。
将一个 '&' 变成一个 '|' 。
将一个 '|' 变成一个 '&' 。
注意:'&' 的 运算优先级 与 '|' 相同 。计算表达式时,括号优先级 最高 ,然后按照 从左到右 的顺序运算。


示例 1:

输入:expression = "1&(0|1)"
输出:1
解释:我们可以将 "1&(0|1)" 变成 "1&(0&1)" ,执行的操作为将一个 '|' 变成一个 '&' ,执行了 1 次操作。
新表达式的值为 0 。
示例 2:

输入:expression = "(0&0)&(0&0&0)"
输出:3
解释:我们可以将 "(0&0)&(0&0&0)" 变成 "(0|1)|(0&0&0)" ,执行了 3 次操作。
新表达式的值为 1 。
示例 3:

输入:expression = "(0|(1|0&1))"
输出:1
解释:我们可以将 "(0|(1|0&1))" 变成 "(0|(0|0&1))" ,执行了 1 次操作。
新表达式的值为 0 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-cost-to-change-the-final-value-of-expression
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

当时没时间了,就看了个题,估计是动态规划
直接看注释吧,这题,我估计还得练个几百道才能在竞赛时间内做出来

class Solution {
    //用一个二元组(x,y), 其中x表示将对应表达式的值变为 0,需要的最少操作次数,y 表示将对应表达式的值变为 1,需要的最少操作次数
    Stack<int[]> num = new Stack<>();   //数字栈
    Stack<Character> ops = new Stack<>();   //符号栈

    public int minOperationsToFlip(String expression) {
        for (int i = 0; i < expression.length(); i++) {
            //当前字符
            char c = expression.charAt(i);
            //如果是数字
            if (Character.isDigit(c)) {
                //如果是0,那么
                if (c == '0')
                    num.add(new int[]{0, 1});
                else
                    num.add(new int[]{1, 0});
            //如果是左括号
            } else if (c == leetcode-852-山脉数组的峰顶索引

[LeetCode] 852. 山脉数组的峰顶索引

Python描述 LeetCode 852. 山脉数组的峰顶索引

LeetCode——852. 山脉数组的峰顶索引(Java)

力扣(LeetCode) 852. 山脉数组的峰顶索引

LeetCode 852. 山脉数组的峰顶索引