leetcode_11. Container With Most Water
一,問題:
Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
翻譯:
給定n個非負整數a1,a2,…,an,其中每個代表座標(i,ai)處的一個點。 繪製n條垂直線,使得線i的兩個端點處於(i,ai)和(i,0)處。 找到兩條線,它們與x軸一起形成一個容器,以使容器包含最多的水。
注意:您不得傾斜容器(即木板效應),並且n至少為2。
二,思路:
1,暴力法:直接通過雙重迴圈遍歷,找出結果。
2,等值線法:其實還是針對法的翻版,找出n1對應的n2等值線,從而針對找尋對應獲得最大值的n2。
三,程式碼:
1.V1:
func maxArea(height []int) int {
maxarea:=0
for k:=0;k<len(height)-1;k++{
for k2:=k+1;k2<len(height);k2++{
minheight:=height[k]
if height[k2]<height[k]{
minheight=height[k2]
}
smaxarea:=(k2-k)*int(minheight)
if smaxarea>maxarea{
maxarea=smaxarea
}
}
}
return maxarea
}
Runtime:648ms,15.04%
根據上一次的經驗,我將第二個遍歷從右邊開始。因為這樣出現更大結果的可能性更高。
並且將內部一些方法提取出去。
最重要的是方法提取出去後,我可以節省一定的記憶體(如smaxarea)。
2.V2:
func maxArea(height []int) int {
maxarea:=0
for k:=0;k<len(height)-1;k++{
for k2:=len(height)-1;k2>k;k2--{
maxarea=max(maxarea,(k2-k)*min(height[k],height[k2]))
}
}
return maxarea
}
func min(a,b int) int {
if a<b{
return a
}else{
return b
}
}
func max(a,b int) int {
if a>b{
return a
}else{
return b
}
}
Runtime:592 ms,23.31%
雖然有所提高,但是依舊差距很大。所以必然存在巨大效能的提升點。
經過思考,我想到一個特性,當我在第二個迴圈內找到的高度比第一個迴圈內的高度高時,那麼這次計算的結果必然是第二個迴圈這個迴圈中最大的結果,我就可以break了。這樣我將會節省巨大的時間。
原因是我水桶矩形的高度最高也就是第一個迴圈中的高度(取最小值嘛),寬度必然是逐步減小的。(我是從兩邊往中間遍歷的)
3.V3:
func maxArea(height []int) int {
maxarea:=0
for k:=0;k<len(height)-1;k++{
for k2:=len(height)-1;k2>k;k2--{
if height[k]<height[k2]{
maxarea=max(maxarea,(k2-k)*height[k])
break
}else{
maxarea=max(maxarea,(k2-k)*height[k2])
}
}
}
return maxarea
}
func max(a,b int) int {
if a>b{
return a
}else{
return b
}
}
Runtime:112 ms,33.83%
也許比例提高不多,但是實際執行時間直接提高了五倍。這簡直是跨越性的提升。
為了程式碼可讀性,以及小的修改,讓我簡單地整理一下程式碼。
4.V4:
func maxArea(height []int) int {
maxarea:=0
for left:=0;left<len(height)-1;left++{
for right:=len(height)-1;right>left;right--{
if height[left]<height[right]{
maxarea=max(maxarea,(right-left)*height[left])
break
}else{
maxarea=max(maxarea,(right-left)*height[right])
}
}
}
return maxarea
}
func max(a,b int) int {
if a>b{
return a
}else{
return b
}
}
Runtime: 104 ms,33.83%
小有提升,關鍵這樣看起來很舒服。
四,他人程式碼:
1.最佳程式碼:
func min(a, b int) int {
if a < b {
return a
}else{
return b
}
}
func max(a, b int) int {
if a < b {
return b
}else{
return a
}
}
func maxArea(height []int) int{
area, left, right := 0, 0, len(height)-1
for left < right {
h := min(height[left], height[right])
area = max(area, h*(right-left))
for ; left < right && height[left] <= h; left++{
}
for ; left < right && height[right] <= h; right--{
}
}
return area
}
Runtime:16ms,100%
2.分析:
其實這裡面,有兩處很精彩。
首先是迴圈判斷條件 left<right。這個條件的精彩之處是它與之前程式碼中
if height[left]<height[right]{
maxarea=max(maxarea,(right-left)*height[left])
break
}else{
maxarea=max(maxarea,(right-left)*height[right])
}
的良好配合。從兩個方面節省了時間。可惜我只注意到了其在第二個迴圈的價值。並沒有將之聯絡到第一個迴圈。在理解這點之後,我完善了自己的程式碼:
V5:
func maxArea(height []int) int {
length:=len(height)
left,right,maxarea:=0,length-1,0
for ;left<right;left++{
for {
if height[left]<=height[right]{
maxarea=max(maxarea,(right-left)*height[left])
break
}else{
maxarea=max(maxarea,(right-left)*height[right])
}
right--
}
}
return maxarea
}
func max(a,b int) int {
if a>b{
return a
}else{
return b
}
}
Runtime: 20 ms,82.71%
這兩個語句結合起來,就從內外兩個迴圈節省時間了。需要好好理解。
(由於最近很忙,忙得有的部落格都寫得差不多了,卻沒時間修飾一下。估計之後部落格會寫得比較粗糙一些。)