题目链接: 面试题1
有关题目
求数组中比左边元素都大同时比右边元素都小的元素,返回这些元素的索引
要求时间复杂度O(N)
示例一:
输入:[2, 3, 1, 8, 9, 20, 12]
输出:3, 4
解释:数组中 8, 9 满足题目要求,他们的索引分别是 3、4
题解
法一:暴力法
思路:
遍历数组,对于每个元素分别往前、往后遍历一下
看看是否它是否满足条件。
伪代码如下
for(int i = 0; i < n; i ++) {
for(int j = 0; j < i; j ++) {
//左侧是否都比它小
}
for(int k = j + 1; k < n; k ++) {
//右侧是否都比它大
}
//若两条件均满足则记录下来
}
法二:动态规划
思路:
外层循环O(N)时间复杂度,无法优化,我们优化暴力法中内层循环
对于下标为i(2 <= i <= n - 2),i左边的数字全部小于
nums[i],右边数字全部大于nums[i]
则满足nums[i] > left_max[i] && nums[i] < right_min[i]
同时我们使用以空间换取时间的做法,将空间复杂度优化到O(N)
vector<int> findIndex(vector<int> nums) {
vector<int> res;
int n = nums.size();
vector<int> left_max(n, INT_MIN);
vector<int> right_min(n, INT_MAX);
for (int i = 1; i < n; i++) {
left_max[i] = max(left_max[i - 1], nums[i - 1]);
}
for (int i = n - 2; i >= 0; i--) {
right_min[i] = min(right_min[i + 1], nums[i + 1]);
}
for (int i = 0; i < n; i++) {
if (left_max[i] < nums[i] && nums[i] < right_min[i]) {
res.push_back(i);
}
}
return res;
}
时间复杂度:O(N)
空间复杂度:O(N)
法三:单调栈
思路:
一侧可以保持一个极值,另一侧空间换时间,记录该位置的极值
找到能满足题干的数组元素下标就可以了
int *findIndex(int* nums, int numsSize){
int len = numsSize;
int right_min[numsSize];
right_min[len - 1] = nums[len - 1];
for (int i = len - 2; i > 0; i--){
//记录每一个元素,对应的数组右侧的最小值
right_min[i] = fmin(right_min[i + 1], nums[i]);
}
int left_max = nums[0];
int ans[len], ansSize = 0;
for (int i = 1; i < len - 1; i++){
if (left_max < nums[i]){
left_max = nums[i];
if (num[i] < right_min[i + 1]){
ans[ansSize++] = i;
}
}
}
}
时间复杂度:O(N)
空间复杂度:O(N)