问题描述
小U有一个整数数组 A,他想知道其中的坡的最大宽度。一个坡是指满足条件的元组 (i, j),其中 i < j 且 A[i] <= A[j]。这样的坡的宽度定义为 j - i。请你帮小U找出数组 A 中的坡的最大宽度。如果不存在符合条件的坡,则返回 0。
输入输出
-
输入:
A:一个整数数组。
-
输出:
- 一个整数,表示数组
A中的坡的最大宽度。如果不存在符合条件的坡,则返回0。
- 一个整数,表示数组
测试样例
-
样例1:
- 输入:
A = [6, 0, 8, 2, 1, 5] - 输出:
4 - 解释:最大坡的宽度是
5 - 1 = 4,对应元组(1, 5)。
- 输入:
-
样例2:
- 输入:
A = [9, 7, 1, 0, 3, 9, 2, 9, 4, 1] - 输出:
7 - 解释:最大坡的宽度是
9 - 2 = 7,对应元组(2, 9)。
- 输入:
-
样例3:
- 输入:
A = [3, 3, 3, 3, 3] - 输出:
4 - 解释:最大坡的宽度是
4 - 0 = 4,对应元组(0, 4)。
- 输入:
思路解析
1. 暴力解法
最直接的方法是使用两层循环,遍历所有可能的 (i, j) 组合,检查是否满足 A[i] <= A[j],并计算坡的宽度。这种方法的时间复杂度为 O(n^2),在数组较大时效率较低。
func solution(A []int) int {
max:=0
for i:=0;i<len(A)-1&&len(A)-1-i>max;i++{
for j:=len(A)-1;j>i;j--{
if A[i]<=A[j]{
if max<j-i{
max=j-i
}
break
}
}
}
return max
}
2. 优化解法
我们可以通过维护一个单调递减栈来优化这个过程。具体步骤如下:
- 从左到右遍历数组,维护一个单调递减栈,栈中存储的是数组的下标。
- 从右到左遍历数组,对于每个元素,检查栈顶元素是否满足
A[i] <= A[j],如果满足,则计算坡的宽度并更新最大宽度。 - 如果栈顶元素不满足条件,则弹出栈顶元素,继续检查下一个栈顶元素。
代码实现
package main
import (
"fmt"
)
func solution(A []int) int {
n := len(A)
if n == 0 {
return 0
}
// 单调递减栈
stack := make([]int, 0)
// 从左到右遍历数组,维护单调递减栈
for i := 0; i < n; i++ {
if len(stack) == 0 || A[i] < A[stack[len(stack)-1]] {
stack = append(stack, i)
}
}
maxWidth := 0
// 从右到左遍历数组,计算最大坡的宽度
for j := n - 1; j >= 0; j-- {
for len(stack) > 0 && A[j] >= A[stack[len(stack)-1]] {
width := j - stack[len(stack)-1]
if width > maxWidth {
maxWidth = width
}
stack = stack[:len(stack)-1]
}
}
return maxWidth
}
代码解析
-
初始化:
n:数组A的长度。stack:单调递减栈,存储数组的下标。
-
维护单调递减栈:
- 从左到右遍历数组
A,如果当前元素A[i]小于等于栈顶元素对应的值,则将当前下标i压入栈中。
- 从左到右遍历数组
-
计算最大坡的宽度:
- 从右到左遍历数组
A,对于每个元素A[j],检查栈顶元素是否满足A[j] >= A[stack[len(stack)-1]]。 - 如果满足条件,计算坡的宽度
j - stack[len(stack)-1],并更新maxWidth。 - 弹出栈顶元素,继续检查下一个栈顶元素。
- 从右到左遍历数组
-
返回结果:
- 返回
maxWidth,表示数组A中的坡的最大宽度。
- 返回
总结
通过维护一个单调递减栈,我们可以将时间复杂度优化到 O(n),从而高效地计算出数组 A 中的坡的最大宽度。这种方法在处理大规模数据时也能保持较高的效率。