题目描述
给定一个不含有重复值的数组 arr,找到每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 小的位置。返回所有位置相应的信息。
举例:
输入:
arr = {3, 4, 1, 5, 6, 2, 7}
返回如下二维数组作为结果:
{
{-1, 2}, // -1表示不存在,整体含义为:arr[0]左边离arr[0]最近且比arr[0]小的是arr[-1],
// arr[0]右边离arr[0]最近且比arr[0]小的是arr[2],
{ 0, 2},
{-1, -1},
{ 2, 5},
{ 3, 5},
{ 2, -1},
{ 5, -1},
}
题目解析
暴力
class Solution {
std::vector<std::vector<int>> getNearLess(std::vector<int> arr){
int size = arr.size();
std::vector<std::vector<int>> res(size, std::vector<int>(2));
for (int i = 0; i < size; ++i) {
int leftLessIndex = -1, rightLessIndex = -1;
int curr = i - 1;
while (curr >= 0){
if(arr[curr] < arr[i]){
leftLessIndex = curr;
break;
}
curr--;
}
curr = i +1;
while (curr < size){
if(arr[curr] < arr[i]){
rightLessIndex = curr;
break;
}
curr++;
}
res[i][0] = leftLessIndex;
res[i][1] = rightLessIndex;
}
return res;
}
};
单调栈
当数组中没有重复值时
求比arr[i]大的左右值
(1) 准备一个单调递增栈,从小到大增长。栈中数据存储的是索引
(2)然后开始遍历原数组,当遍历完3,4时,发现满足要求,就将3,4的索引压入栈中
(2)当遍历到2时,发现不满足单调栈的要求,当前数不能压栈,怎么办呢?
无论如何,当前数都是要压栈的,所以就要将栈中的某些数出栈,出栈的瞬间,就得到了这个数的某些信息。
所以1—>4出栈:
- 右边比1—>4小的数是令它出栈的那个数,就是2—>2
- 左边比1—>4小的数:因为4出栈之后,栈不为空,所以就是栈顶元素0---->3
那么1—>4出栈了之后,2—>2能不能进栈呢?不能,0—>3比2—>2大,所以0—>3也要出栈
- 右边比0—>3小的数是令它出栈的那个数,就是2—>2
- 左边比0—>3小的数:因为0—>3出栈后,栈为空了,所以左边没有比0—>3小的数,填**-1**
现在2—>2可以进栈了
(3)继续遍历
然后可以得到:
- 3—>6:2—>2,4—>1
- 2—>2:-1,4—>1
(4)继续遍历
- 5—>7:4—>1,6---->0
(5)现在所有数据都遍历完成了,但是栈不为空
我们要倒空栈。因为右边没有可以使得出栈的元素,所以右边都没有把它小的数
- 6—>0
- 左边比它小的数:因为出栈时栈顶不为空,所以就是栈顶元素4—>1
- 右边比它小的数:因为没有可以使得出栈的元素,所以数组右边没有比它小的数,填-1
- 4—>1:-1,-1
当数组中有重复值时
(1) 准备一个单调递增栈,从小到大增长。栈中数据存储的是索引链表
(2)遍历数组
4—>4不能放到5的上面,所以 {3}—>5 要结算答案
- {3}—>5
- 右边比它小的数:谁令我出栈?4—>4
- 左边比它小的数:我压着的那个链表的最后一个位置:3—>5
那么现在4—>4能不能落在栈顶呢?不能,因为栈顶元素也是4,所以合并
(3)继续遍历数组
5—>3能不能压栈?不能,栈顶元素必须出栈,出栈的元素要结算答案。出栈的元素是{2,4},所以分别对{2,4}结算答案
- 4—>4:1—>3,5—>3
- 2---->4:1—>3,5—>3
可以看出,它们的答案是一样的
…
实现
当没有重复值
class Solution {
std::vector<std::vector<int>> getNearLessNoRepeat(std::vector<int> arr){
int size = arr.size();
std::vector<std::vector<int>> res(size, std::vector<int>(2));
std::stack<int> stack;
for (int i = 0; i < size; ++i) {
while (!stack.empty() && arr[stack.top()] > arr[i]){
int j = stack.top(); stack.pop();
int leftLessIndex = stack.empty() ? -1 : stack.top();
res[j][0] = leftLessIndex;
res[j][1] = i;
}
stack.push(i);
}
while (!stack.empty()){
int j = stack.top(); stack.pop();
int leftLessIndex = stack.empty() ? -1 : stack.top();
res[j][0] = leftLessIndex;
res[j][1] = -1;
}
return res;
}
};
当有重复值
class Solution {
std::vector<std::vector<int>> getNearLess(std::vector<int> arr){
int size = arr.size();
std::vector<std::vector<int>> res(size, std::vector<int>(2));
std::stack<std::list<int>> stack;
for (int i = 0; i < size; ++i) {
while (!stack.empty() && arr[stack.top().front()] > arr[i]){
std::list<int> js = stack.top(); stack.pop();
int leftLessIndex = stack.empty() ? -1 : stack.top().back();
while (!js.empty()){
auto j = js.front(); js.pop_front();
res[j][0] = leftLessIndex;
res[j][1] = i;
}
}
if(!stack.empty() && arr[stack.top().front()] == arr[i]){
stack.top().push_back(i);
}else{
std::list<int> l;
l.push_back(i);
stack.push(l);
}
}
while (!stack.empty()){
std::list<int> js = stack.top(); stack.pop();
int leftLessIndex = stack.empty() ? -1 : stack.top().back();
while (!js.empty()){
auto j = js.front(); js.pop_front();
res[j][0] = leftLessIndex;
res[j][1] = -1;
}
}
return res;
}
};
对数器
其他
求比arr[i]大的左右值