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-山脉数组的峰顶索引
Python描述 LeetCode 852. 山脉数组的峰顶索引