
专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。
一、题目描述
一线运维人员在对通话流量进行监控,每一段时间内都是出现流量的高峰,流量有高有低形成一个个波峰波谷,运维人员想找到流量变化最快的波峰,你可以帮助他吗?
给定一个整数数组nums,代表采样点的流量值,请找到满足以下条件的三元组 (i,j,k): 其中i<j<k,nums[j] > nums[i]且nums[j] > nums[k](即是峰顶),并找到所有满足条件的三元组中(k-i)的最小值
二、输入描述
第一行是一个整数n,表示有几个元素
第一行为n个整数,表示数组中的n个元素,0<= n < =100000
三、输出描述
返回所有满足条件的三元组中(k-i)的最小值。若不存在,返回-1。
四、测试用例
测试用例1:
1、输入
6
3 5 4 7 2 1
2、输出
2
3、说明
满足条件的三元组为[0, 1, 2],距离2
测试用例2:
1、输入
4
4 3 2 1
2、输出
-1
3、说明
无法找到满足条件的三元组,返回-1
五、解题思路
目标是最小化 k-i,且存在峰顶 j:i<j<k、nums[j] > nums[i] 且 nums[j] > nums[k]。
对固定峰顶 j,k-i = (j-i)+(k-j),左右两侧距离互不影响,因此应选离 j 最近的左侧严格更小元素与离 j 最近的右侧严格更小元素。
使用单调递增栈分别求每个位置的“最近左侧严格更小”和“最近右侧严格更小”,时间 O(n),空间 O(n),适合 n≤100000。
六、Python算法源码
import sys
def main():
data = sys.stdin.read().strip().split()
if not data:
print(-1)
return
nums = list(map(int, data))
n = len(nums)
if n < 3:
print(-1)
return
left_less = [-1] * n
right_less = [-1] * n
# 单调递增栈,栈中索引对应值严格递增
stack = []
for i in range(n):
while stack and nums[stack[-1]] >= nums[i]:
stack.pop()
left_less[i] = stack[-1] if stack else -1
stack.append(i)
stack = []
for i in range(n - 1, -1, -1):
while stack and nums[stack[-1]] >= nums[i]:
stack.pop()
right_less[i] = stack[-1] if stack else -1
stack.append(i)
ans = None
for j in range(n):
if left_less[j] != -1 and right_less[j] != -1:
dist = right_less[j] - left_less[j]
ans = dist if ans is None else min(ans, dist)
print(-1 if ans is None else ans)
if __name__ == "__main__":
main()
七、JavaScript算法源码
const fs = require('fs');
const input = fs.readFileSync(0, 'utf8').trim();
if (input.length === 0) {
console.log(-1);
process.exit(0);
}
const nums = input.split(/\s+/).map(Number);
const n = nums.length;
if (n < 3) {
console.log(-1);
process.exit(0);
}
const leftLess = new Array(n).fill(-1);
const rightLess = new Array(n).fill(-1);
// 单调递增栈,保存索引
let stack = [];
for (let i = 0; i < n; i++) {
while (stack.length && nums[stack[stack.length - 1]] >= nums[i]) {
stack.pop();
}
leftLess[i] = stack.length ? stack[stack.length - 1] : -1;
stack.push(i);
}
stack = [];
for (let i = n - 1; i >= 0; i--) {
while (stack.length && nums[stack[stack.length - 1]] >= nums[i]) {
stack.pop();
}
rightLess[i] = stack.length ? stack[stack.length - 1] : -1;
stack.push(i);
}
let ans = Infinity;
for (let j = 0; j < n; j++) {
if (leftLess[j] !== -1 && rightLess[j] !== -1) {
ans = Math.min(ans, rightLess[j] - leftLess[j]);
}
}
console.log(ans === Infinity ? -1 : ans);
八、C算法源码
#include <stdio.h>
#include <stdlib.h>
int main() {
int capacity = 1024;
int *nums = (int *)malloc(sizeof(int) * capacity);
int n = 0;
// 读取所有整数
while (1) {
int x;
if (scanf("%d", &x) != 1) break;
if (n >= capacity) {
capacity *= 2;
nums = (int *)realloc(nums, sizeof(int) * capacity);
}
nums[n++] = x;
}
if (n < 3) {
printf("-1");
free(nums);
return 0;
}
int *leftLess = (int *)malloc(sizeof(int) * n);
int *rightLess = (int *)malloc(sizeof(int) * n);
int *stack = (int *)malloc(sizeof(int) * n);
int top = -1;
for (int i = 0; i < n; i++) leftLess[i] = -1;
for (int i = 0; i < n; i++) rightLess[i] = -1;
// 左侧最近严格更小
for (int i = 0; i < n; i++) {
while (top >= 0 && nums[stack[top]] >= nums[i]) {
top--;
}
leftLess[i] = (top >= 0) ? stack[top] : -1;
stack[++top] = i;
}
// 右侧最近严格更小
top = -1;
for (int i = n - 1; i >= 0; i--) {
while (top >= 0 && nums[stack[top]] >= nums[i]) {
top--;
}
rightLess[i] = (top >= 0) ? stack[top] : -1;
stack[++top] = i;
}
int ans = 2147483647;
for (int j = 0; j < n; j++) {
if (leftLess[j] != -1 && rightLess[j] != -1) {
int dist = rightLess[j] - leftLess[j];
if (dist < ans) ans = dist;
}
}
if (ans == 2147483647) printf("-1");
else printf("%d", ans);
free(nums);
free(leftLess);
free(rightLess);
free(stack);
return 0;
}
九、C++算法源码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
vector<int> nums;
int x;
// 读取所有整数
while (cin >> x) nums.push_back(x);
int n = nums.size();
if (n < 3) {
cout << -1;
return 0;
}
vector<int> leftLess(n, -1), rightLess(n, -1);
vector<int> stack;
// 左侧最近严格更小
for (int i = 0; i < n; i++) {
while (!stack.empty() && nums[stack.back()] >= nums[i]) {
stack.pop_back();
}
leftLess[i] = stack.empty() ? -1 : stack.back();
stack.push_back(i);
}
// 右侧最近严格更小
stack.clear();
for (int i = n - 1; i >= 0; i--) {
while (!stack.empty {
while (!stack.empty() && nums[stack.back()] >= nums[i]) {
stack.pop_back();
}
rightLess[i] = stack.empty() ? -1 : stack.back();
stack.push_back(i);
}
int ans = INT_MAX;
for (int j = 0; j < n; j++) {
if (leftLess[j] != -1 && rightLess[j] != -1) {
ans = min(ans, rightLess[j] - leftLess[j]);
}
}
cout << (ans == INT_MAX ? -1 : ans);
return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 双机位C卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。

259

被折叠的 条评论
为什么被折叠?



