持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情
前言
小白算法比较菜,希望能激励我每日更新,从leetcode第一题开始,2022年目标300题,记录从0到1的全过程!!
力扣第 312 场周赛
力扣第 312 场周赛-力扣
a了三题,2000以内,小上10几分。第三题有点离谱,给的例子太基础了,修改了代码之后根本试不出来对不对,错八次可真是,,,,不罚时的话能到1150名呢(当然只能想想)
这个第三题可得好好说道说道!!!
2420. 找到所有好下标
给你一个大小为 n 下标从 0 开始的整数数组 nums 和一个正整数 k 。
对于 k <= i < n - k 之间的一个下标 i ,如果它满足以下条件,我们就称它为一个 好 下标:
下标 i 之前 的 k 个元素是 非递增的 。
下标 i 之后 的 k 个元素是 非递减的 。
按 升序 返回所有好下标。
示例 1
输入:nums = [2,1,1,1,3,4,1], k = 2
输出:[2,3]
解释:数组中有两个好下标:
-
下标 2 。子数组 [2,1] 是非递增的,子数组 [1,3] 是非递减的。
-
下标 3 。子数组 [1,1] 是非递增的,子数组 [3,4] 是非递减的。
-
注意,下标 4 不是好下标,因为 [4,1] 不是非递减的。
示例 2
- 输入: nums = [2,1,1,2], k = 2
- 输出: []
- 解释: 数组中没有好下标。
提示
n == nums.length3 <= n <= 1051 <= nums[i] <= 1061 <= k <= n / 2
解析1
开始并没想到什么好的思路,然后还把题意理解错了几次。
注意
1.要判断的是i前面的k个和后面的k个,不包括i
2.非递增和非递减要理解好!!!
先说暴力吧,暴力确实是简单,结果过不了,如代码1
代码1
暴力很简单,但是作为第三题,能让你用暴力就做出来!?别想了,没门。
class Solution {
public List<Integer> goodIndices(int[] nums, int k) {
int left = k;
int right = nums.length - k - 1;
if (right < left) return new ArrayList<>();
List<Integer> res = new ArrayList<>();
while (left <= right) {
if (fun(nums, left, k)) {
res.add(left);
}
left++;
}
return res;
}
public boolean fun(int[] nums, int index, int k) {
for (int i = 1; i < k; i++) {
if (!(nums[index + i + 1] >= nums[index + i])) {
return false;
}
if (!(nums[index - i - 1] >= nums[index - i])) {
return false;
}
}
return true;
}
}
解析2
那就暴力剪枝,还是从前往后遍历,如果是在i之前的有个元素发现了异常,那么下次就直接跳到这个异常的元素之后。
直接这么说大家可能不明白,那么看图。
如图,如果在查找i时,发现i-2(这里用x代表他的序号)不符合条件,那么就不需要判断i+1了,直接跳到x+k+1就好。
同理,尾部也可以剪枝
在判断i是否满足条件时,发现i+2(这里用x代替序号)不符合条件,那么就不需要判断i+1了,直接令i=x就可以了
代码2
果然,剪枝之后就过了。
class Solution {
int num;
public List<Integer> goodIndices(int[] nums, int k) {
List<Integer> res = new ArrayList<>();
if (k==1) {
for (int i = 1; i < nums.length - 1; i++) {
res.add(i);
}
return res;
}
int left = k;
int right = nums.length - k - 1;
if (right < left) return res;
while (left <= right) {
boolean fun = fun(nums, left, k);
if (fun) {
res.add(left);
while (left <= right && fun && left + k + 1 < nums.length - 1) {
fun = nums[left - 1] >= nums[left] && nums[left + k] <= nums[left + k + 1];
left++;
if (fun) {
res.add(left);
}
}
left++;
} else {
if (num < left) {
left = num + k + 1;
} else {
left = num - 1;
}
}
}
return res;
}
public boolean fun(int[] nums, int index, int k) {
for (int i = 1; i < k; i++) {
if (!(nums[index + i + 1] >= nums[index + i])) {
num = index + i + 1;
return false;
}
if (!(nums[index - i - 1] >= nums[index - i])) {
num = index - i - 1;
return false;
}
}
return true;
}
}
耗时也还ok
解析3
之后看别人的题解,有一个更简便的方法,能想到这确实真的很牛。
用两个数组,分别记录序号i后面非递减的元素个数,记录了i前面非递增的元素个数。
比如
遍历这两个数组,判断rise[i-1]>=k && decline[i+1]>=k就可以了
代码2
思路又简单又快!!大佬还是强。
class Solution {
public List<Integer> goodIndices(int[] nums, int k) {
int[] rise = new int[nums.length];
int[] decline = new int[nums.length];
int index = 1;
rise[0] = 1;
for (int i = 1; i < rise.length; i++) {
if (nums[i] <= nums[i-1]) {
index++;
}else {
index = 1;
}
rise[i] = index;
}
index = 1;
decline[decline.length - 1] = 1;
for (int i = decline.length - 2; i >= 0; i--) {
if (nums[i] <= nums[i+1]) {
index++;
} else {
index = 1;
}
decline[i] = index;
}
ArrayList<Integer> res = new ArrayList<>();
for (int i = k; i < nums.length - k; i++) {
if (rise[i-1]>=k && decline[i+1]>=k) {
res.add(i);
}
}
return res;
}
}
第一、二题连接如下
[杨小白]_leetcode_力扣第 312 场周赛-第一、二题
第四题连接如下-2430. 对字母串可执行的最大删除数
[杨小白]_leetcode_力扣第 312 场周赛-第四题
3.结束
前两题都不难,基本200题量的同学就可以做出来了,第三题的话,最后的方法确实很巧妙,还是得多见多写。第四题还是无从下手,gogogo,刷题刷题,每天一道,三年1000道!!!!