解法一 双指针
算法
左右边界作为所选的两个边,计算可以盛的水的容量。如果左边的边小,则剔除次边因此左边界向右移,否则右边界左移(即剔除最右侧边),计算当前的水容量。循环至左边界索引大于等于右边界索引。
证明
在当前边集中,以左右边界高度小的边 做边界能盛的水的最大值就是当前计算的值。因为和别的边匹配 最小高度不可能高于自身高度, 并且宽度不可能大于当前的宽度(因为现在所取两个边是目前边的边界)。
因此可以将小的边剔除,因为以他为边的最大值已经计算。
代码
go实现版本
func maxArea(height []int) int {
var max int
var i, j = 0, len(height)-1
for ; i < j; {
var minHeight int
var wide =j-i
if height[i] < height[j] {
minHeight =height[i]
i++
}else {
minHeight =height[j]
j--
}
if tmp := minHeight * wide; max < tmp {
max = tmp
}
}
return max
}
解法二:优先队列
算法:
从左到右计算优先队列。不在优先队列的边a和任意边b组合盛的水不可能比在优先队列中边c和d组合多,原因是不在优先队列中说明优先队列中存在 在其左侧的边c的边长大于边a,不然a就会进入优先队列。
然后计算从右到左的优先队列。两个优先队列正交。
代码
// 优先队列解法
// 以最右侧为右边,从最左侧开始向右扫描,分别为a b c ,当扫描完a后扫描b,如果b比左侧的最大值小 那么水量肯定小 则直接跳过。从左到右组成一个优先队列.被剔除的点不可能是最优解
// 同理以最左侧为边,从右向左求优先队列。被踢的点也不可能为最优解
type Queue struct {
index int
value int
}
func maxArea1(height []int) int {
var leftPriority []Queue
for i := 0; i < len(height); i++ {
if len(leftPriority) == 0 {
leftPriority = append(leftPriority, Queue{index: i, value: height[i]})
continue
}
if height[i] > leftPriority[len(leftPriority)-1].value {
leftPriority = append(leftPriority, Queue{index: i, value: height[i]})
}
}
var rightPriority []Queue
for i := len(height) - 1; i >= 0; i-- {
if len(rightPriority) == 0 {
rightPriority = append(rightPriority, Queue{index: i, value: height[i]})
continue
}
if height[i] > rightPriority[len(rightPriority)-1].value {
rightPriority = append(rightPriority, Queue{index: i, value: height[i]})
}
}
var max int
for i := 0; i < len(leftPriority); i++ {
for j := 0; j<len(rightPriority); j++ {
if rightPriority[j].index > leftPriority[i].index {
minHigh := rightPriority[j].value
if rightPriority[j].value > leftPriority[i].value {
minHigh = leftPriority[i].value
}
if tmpMax := minHigh * (rightPriority[j].index - leftPriority[i].index); tmpMax > max {
max = tmpMax
}
continue
}
break
}
}
return max
}