我们经常会遇到这种类型的问题:
针对这种问题,有两种方式进行求解:
O(N)
;O(N的平方)
;本文主要介绍单调栈的方法求解。
注:为方便问题叙述,我们这里返回的都是目标数的下标。
给定一个数组,针对数组中每个元素,找出其左边第一个比它大的数的下标。
如下图所示,针对元素黄色5
,其左边第一个比它大的数为绿色8
,则应该返回1(绿色8的下标
)
根据小窍门,很容易写出如下代码(注:如果左边没找到比它大的数,返回-1):
public int[] getLeftBiggerIndexByMethodStack(int[] nums) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[nums.length];
for (int i = nums.length - 1; i >= 0; i--) {
if (stack.isEmpty()) {
stack.push(i);
ans[i] = -1;
} else {
while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) {
int x = stack.pop();
ans[x] = i;
}
stack.push(i);
ans[i] = -1;
}
}
return ans;
}
给定一个数组,针对数组中每个元素,找出其左边第一个比它小的数的下标。
如下图所示,针对元素黄色5
,其左边第一个比它小的数为绿色1
,则应该返回3(绿色1的下标
)。
根据小窍门,很容易写出如下代码(注:如果左边没找到比它小的数,返回-1):
public int[] getLeftSmallerIndexByMethodStack(int[] nums) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[nums.length];
for (int i = nums.length - 1; i >= 0; i--) {
if (stack.isEmpty()) {
stack.push(i);
ans[i] = -1;
} else {
while (!stack.isEmpty() && nums[stack.peek()] > nums[i]) {
int x = stack.pop();
ans[x] = i;
}
stack.push(i);
ans[i] = -1;
}
}
return ans;
}
给定一个数组,针对数组中每个元素,找出其右边第一个比它大的数的下标。
如下图所示,针对元素黄色5
,其右边第一个比它大的数为绿色6
,则应该返回5(绿色6的下标
)。
根据小窍门,很容易写出如下代码(注:如果右边没找到比它大的数,返回数组长度):
public int[] getRightBiggerIndexByMethodStack(int[] nums) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
if (stack.isEmpty()) {
stack.push(i);
ans[i] = nums.length;
} else {
while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) {
int x = stack.pop();
ans[x] = i;
}
stack.push(i);
ans[i] = nums.length;
}
}
return ans;
}
给定一个数组,针对数组中每个元素,找出其右边第一个比它小的数的下标。
如下图所示,针对元素黄色5
,其右边第一个比它小的数为绿色2
,则应该返回7(绿色2的下标
)。
根据小窍门,很容易写出如下代码(注:如果右边没找到比它的数,返回数组长度):
public int[] getRightSmallerIndexByMethodStack(int[] nums) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
if (stack.isEmpty()) {
stack.push(i);
ans[i] = nums.length;
} else {
while (!stack.isEmpty() && nums[stack.peek()] > nums[i]) {
int x = stack.pop();
ans[x] = i;
}
stack.push(i);
ans[i] = nums.length;
}
}
return ans;
}
为验证代码的正确性,采用如下方法进行验证:
import java.util.*;
public class Test {
public static void main(String[] args) {
Solution solution = new Solution();
for (int i = 0; i < 1000; i++) {
// 生成长度为100的随机数组
int[] nums = new Random().ints(100).toArray();
// 针对数组中某个数,找到左边第一个比当前数大的数的下标
int[] a = solution.getLeftBiggerIndexByMethodLoop(nums);
int[] b = solution.getLeftBiggerIndexByMethodStack(nums);
boolean ans = solution.check(a, b);
if (!ans) {
System.out.println("error left Closest bigger");
}
a = solution.getLeftSmallerIndexByMethodLoop(nums);
b = solution.getLeftSmallerIndexByMethodStack(nums);
ans = solution.check(a, b);
if (!ans) {
System.out.println("error left Closest smaller");
}
a = solution.getRightBiggerIndexByMethodLoop(nums);
b = solution.getRightBiggerIndexByMethodStack(nums);
ans = solution.check(a, b);
if (!ans) {
System.out.println("error right Closest bigger");
}
a = solution.getRightSmallerIndexByMethodLoop(nums);
b = solution.getRightSmallerIndexByMethodStack(nums);
ans = solution.check(a, b);
if (!ans) {
System.out.println("error right Closest smaller");
}
}
System.out.println("Success");
}
}
import java.util.*;
class Solution {
public int[] getLeftBiggerIndexByMethodStack(int[] nums) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[nums.length];
for (int i = nums.length - 1; i >= 0; i--) {
if (stack.isEmpty()) {
stack.push(i);
ans[i] = -1;
} else {
while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) {
int x = stack.pop();
ans[x] = i;
}
stack.push(i);
ans[i] = -1;
}
}
return ans;
}
public int[] getLeftBiggerIndexByMethodLoop(int[] nums) {
int[] ans = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
boolean flag = false;
for (int j = i - 1; j >= 0; j--) {
if (nums[j] > nums[i]) {
ans[i] = j;
flag = true;
break;
}
}
if (!flag) {
ans[i] = -1;
}
}
return ans;
}
public int[] getLeftSmallerIndexByMethodStack(int[] nums) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[nums.length];
for (int i = nums.length - 1; i >= 0; i--) {
if (stack.isEmpty()) {
stack.push(i);
ans[i] = -1;
} else {
while (!stack.isEmpty() && nums[stack.peek()] > nums[i]) {
int x = stack.pop();
ans[x] = i;
}
stack.push(i);
ans[i] = -1;
}
}
return ans;
}
public int[] getLeftSmallerIndexByMethodLoop(int[] nums) {
int[] ans = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
boolean flag = false;
for (int j = i - 1; j >= 0; j--) {
if (nums[j] < nums[i]) {
ans[i] = j;
flag = true;
break;
}
}
if (!flag) {
ans[i] = -1;
}
}
return ans;
}
public int[] getRightBiggerIndexByMethodStack(int[] nums) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
if (stack.isEmpty()) {
stack.push(i);
ans[i] = nums.length;
} else {
while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) {
int x = stack.pop();
ans[x] = i;
}
stack.push(i);
ans[i] = nums.length;
}
}
return ans;
}
public int[] getRightBiggerIndexByMethodLoop(int[] nums) {
int[] ans = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
boolean flag = false;
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] > nums[i]) {
ans[i] = j;
flag = true;
break;
}
}
if (!flag) {
ans[i] = nums.length;
}
}
return ans;
}
public int[] getRightSmallerIndexByMethodStack(int[] nums) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
if (stack.isEmpty()) {
stack.push(i);
ans[i] = nums.length;
} else {
while (!stack.isEmpty() && nums[stack.peek()] > nums[i]) {
int x = stack.pop();
ans[x] = i;
}
stack.push(i);
ans[i] = nums.length;
}
}
return ans;
}
public int[] getRightSmallerIndexByMethodLoop(int[] nums) {
int[] ans = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
boolean flag = false;
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] < nums[i]) {
ans[i] = j;
flag = true;
break;
}
}
if (!flag) {
ans[i] = nums.length;
}
}
return ans;
}
public boolean check(int[] a, int[] b) {
for (int i = 0; i < a.length; i++) {
if (a[i] != b[i])
return false;
}
return true;
}
}
以下是LeetCode中遇到的单调栈的一些题目,持续更新中……