峰值专题
今日的每日一题和上一次周赛的子序列很相似,都是找峰值的。
Leetcode-162-Find Peak Element
题目链接:https://leetcode-cn.com/problems/find-peak-element/
找到一个数A,要求A大于左右两边邻居的数,返回该数的索引,若有多个,则任意返回一个。
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int l = 0, len = nums.size(), r = len - 1;
while (l < r)
{
int mid = l + r >> 1;
if (nums[mid] > nums[mid + 1]) r = mid;
else l = mid + 1;
}
return l;
}
};
AcWing-3957-子序列
题目链接:
https://www.acwing.com/problem/content/3960/
题目大概的意思是找到任意三个数,同时要保证中间的那个数大于或者小于另外两个数。
- 法一: 对于任一个数(不包括头、尾两个数),记录他左右两边的最大值、最小值的下标。然后遍历一遍,找到其中一个就可以返回。
- 法二: 对于这个题来说,构造一个长度为3的山顶或者山谷即可,只有当整个数组有序时才无解,否则中间必存在一个[拐点]
法一代码:
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 100000 + 1000;
int a[N], lmax[N], rmax[N], lmin[N], rmin[N];
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
lmax[1] = lmin[1] = 1;
for (int i = 2; i <= n; i ++)
{
lmin[i] = lmax[i] = i;
if (a[i] < a[lmax[i - 1]]) lmax[i] = lmax[i - 1];
if (a[i] > a[lmin[i - 1]]) lmin[i] = lmin[i - 1];
}
rmax[n] = rmin[n] = n;
for (int i = n - 1; i > 0; i --)
{
rmax[i] = rmin[i] = i;
if (a[i] < a[rmax[i + 1]]) rmax[i] = rmax[i + 1];
if (a[i] > a[rmin[i + 1]]) rmin[i] = rmin[i + 1];
}
for (int i = 2; i < n; i ++)
{
if (a[i] > a[lmin[i - 1]] && a[i] > a[rmin[i + 1]])
{
printf("3\n%d %d %d\n", lmin[i - 1], i, rmin[i + 1]);
return 0;
}
if (a[i] < a[lmax[i - 1]] && a[i] < a[rmax[i + 1]])
{
printf("3\n%d %d %d\n", lmax[i - 1], i, rmax[i + 1]);
return 0;
}
}
puts("0");
return 0;
}
法二代码:
#include<cstdio>
using namespace std;
const int N = 100000 + 100;
int a[N];
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i ++) scanf("%d", a + i);
for (int i = 1; i < n - 1; i ++) {
if ((a[i] > a[0] && a[i] > a[i + 1]) || (a[i] < a[0] && a[i] < a[i + 1]))
{
printf("3\n%d %d %d\n", 1, i + 1, i + 2);
return 0;
}
}
printf("0\n");
return 0;
}