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.

思路

实在是想不到好的方法,参考了下教程,发现双指针法,真的是简单又明了。
思路是这样的:

  • 现在有两个指针,一个指数组头,一个指数组尾。
  • 一个max变量,用来记录最大的面积
  • 判断两个指针所指的列围起来的面积,与max求最大值
  • 判断两个指针所指的列高低,指向低的那个指针向另一个指针移动
  • 两个指针相遇则退出

这个思路的关键点就是第四条,为何要这么做?
这就好比木桶原理,木桶能装多少水是取决于矮的那块板子的。这个短板就相当于这道题中低的那一列,只要这块短板不被替换,那么另一列再怎么移动,围起来的面积也不会比现在大,因为两个指针是相向运动,它们之间的距离是越来越短的。这就是为什么要判断两列谁短,短的那列要移动。

代码

int maxArea(int* height, int heightSize) {
    int start = 0, max = 0, end = heightSize - 1;
    while(start < end){
        int left = height[start];
        int right = height[end];
        int area = (end - start) * (left > right ? right : left);
        max = max > area ? max : area;
        if(left >= right){
            end--;
        }
        else{
            start++;
        }
    }
    return max;
}

6ms解决,C还是快啊!

总结

以后遇到这种题不能单纯以解决为目标,解决是很简单,O(n2)的方法,大家都会写。还是得以巧妙的方法解决有意思。多学多看吧!

下面的为之前的内容,可不看,暴力破解用例过的

一开始的代码

nt maxArea(int* height, int heightSize) {
    int max = 0;
    if(heightSize == 0 || heightSize == 1){
        return 0;
    }

    for(int i = 0; i < heightSize; i++){
        for(int j = i + 1; j < heightSize; j++){
            int row = j - i;
            int col = height[j] < height[i] ? height[j] : height[i];
            int area = row * col;
            max = max > area ? max : area;
        }
    }

    return max;
}

复杂度为O(N2)超时了

2.0版本

还是超时,不过不是之前的超时用例了

int maxArea(int* height, int heightSize) {
    int max = 0;
    if(heightSize == 0 || heightSize == 1){
        return 0;
    }

    for(int i = 0; i < heightSize; i++){
        if(i <= heightSize / 2){//距离右端远
            int j = heightSize - 1;
            while(j > i){//从右开始,找到高度大于i的第一个也是最远的j
                if(height[j] >= height[i]){
                    //printf("%d * %d | ", height[i], j -i);
                    max = max > (height[i] * (j - i)) ? max : height[i] * (j - i);
                    break;
                }
                else{
                    j--;
                }
            }
            if(j - i < i){//右端的距离小于左端最远的距离,则左端可能存在大于目前面积的列,检查左端
                int k = 0;
                while(k < i && i - k > j - i){
                    if(height[k] >= height[i]){
                        //printf("%d * %d | ", height[i], i-k);
                        max = max > (height[i] * (i - k)) ? max : height[i] * (i - k);
                        break;
                    }
                    else{
                        k++;
                    }
                }
            }
        }
        else{//距离左端远,同上
            int j = 0;
            while(j < i){
                if(height[j] >= height[i]){
                    //printf("%d * %d | ", height[i], i-j);
                    max = max > (height[i] * (i - j)) ? max : height[i] * (i - j);
                    break;
                }
                else{
                    j++;
                }
            }
            if(i - j < heightSize - i - 1){
                int k = heightSize - 1;
                while(k > i && k - i > i - j){
                    if(height[k] >= height[i]){
                        //printf("%d * %d | ", height[i], k -i);
                        max = max > (height[i] * (k - i)) ? max : height[i] * (k - i);
                        break;
                    }
                    else{
                        k--;
                    }
                }
            }
        }
    }

    return max;
}

3.0版

想到在上个版本上更进一步的简便方法,循环时多加个判断条件,可以少判断几次

int maxArea(int* height, int heightSize) {
    int max = 0;
    if(heightSize == 0 || heightSize == 1){
        return 0;
    }

    for(int i = 0; i < heightSize; i++){
        if(height[i] == 0){
            continue;
        }
        if(i <= (heightSize - 1) / 2){//距离右端远
            int j = heightSize - 1;
            while(j > i && ((j - i) > max / height[i])){//从右开始,找到高度大于i的第一个也是最远的j
                if(height[j] >= height[i]){
                    //printf("%d * %d | ", height[i], j -i);
                    max = max > (height[i] * (j - i)) ? max : height[i] * (j - i);
                    break;
                }
                else{
                    j--;
                }
            }
            if(j - i < i){//右端的距离小于左端最远的距离,则左端可能存在大于目前面积的列,检查左端
                int k = 0;
                while(k < i && i - k > j - i){
                    if(height[k] >= height[i]){
                        //printf("%d * %d | ", height[i], i-k);
                        max = max > (height[i] * (i - k)) ? max : height[i] * (i - k);
                        break;
                    }
                    else{
                        k++;
                    }
                }
            }
        }
        else{//距离左端远,同上
            int j = 0;
            while(j < i && ((i - j) > max / height[i])){
                if(height[j] >= height[i]){
                    //printf("%d * %d | ", height[i], i-j);
                    max = max > (height[i] * (i - j)) ? max : height[i] * (i - j);
                    break;
                }
                else{
                    j++;
                }
            }
            if(i - j < heightSize - i - 1){
                int k = heightSize - 1;
                while(k > i && k - i > i - j){
                    if(height[k] >= height[i]){
                        //printf("%d * %d | ", height[i], k -i);
                        max = max > (height[i] * (k - i)) ? max : height[i] * (k - i);
                        break;
                    }
                    else{
                        k--;
                    }
                }
            }
        }
    }

    return max;
}

还是未通过,当测试用例为倒序时,遍历的次数还是会较多,因此改下算法,先算下用例大概为升序还是降序,若为升序则从左向右开始遍历,若为降序,则从右开始向左遍历。
改完了,还是未过…只好根据测试用例,采用暴力破解了

int maxArea(int* height, int heightSize) {
    int max = 0;
    if(heightSize == 0 || heightSize == 1){
        return 0;
    }

    int asc = 1;
    for(int i = 1; i < heightSize; i++){
        if(height[i] < height[i - 1]){
            asc = 0;
            break;
        }
    }
    if(asc == 1){//升序数列
        for(int i = 0; i < heightSize; i++){
            max = max > (heightSize - i - 1) * height[i] ? max : (heightSize - i - 1) * height[i];
        }
        return max;
    }

    int desc = 1;
    for(int i = 0; i < heightSize; i++){
        if(i == heightSize - 1){
            if(height[i] > height[i - 1]){
                desc = 0;
                break;
            }
        }
        else{
            if(height[i] < height[i + 1]){
                desc = 0;
                break;
            }
        }
    }
    if(desc == 1){
        for(int i = heightSize - 1; i >= 0; i--){
            max = max > i * height[i] ? max : i * height[i];
        }
        return max;
    }

    if(asc >= 0){
        for(int i = 0; i < heightSize; i++){
            if(height[i] == 0){
                continue;
            }
            if(i <= (heightSize - 1) / 2){//距离右端远
                int j = heightSize - 1;
                while(j > i && ((j - i) > max / height[i])){//从右开始,找到高度大于i的第一个也是最远的j
                    if(height[j] >= height[i]){
                        //printf("%d * %d | ", height[i], j -i);
                        max = max > (height[i] * (j - i)) ? max : height[i] * (j - i);
                        break;
                    }
                    else{
                        j--;
                    }
                }
                if(j - i < i){//右端的距离小于左端最远的距离,则左端可能存在大于目前面积的列,检查左端
                    int k = 0;
                    while(k < i && i - k > j - i){
                        if(height[k] >= height[i]){
                            //printf("%d * %d | ", height[i], i-k);
                            max = max > (height[i] * (i - k)) ? max : height[i] * (i - k);
                            break;
                        }
                        else{
                            k++;
                        }
                    }
                }
            }
            else{//距离左端远,同上
                int j = 0;
                while(j < i && ((i - j) > max / height[i])){
                    if(height[j] >= height[i]){
                        //printf("%d * %d | ", height[i], i-j);
                        max = max > (height[i] * (i - j)) ? max : height[i] * (i - j);
                        break;
                    }
                    else{
                        j++;
                    }
                }
                if(i - j < heightSize - i - 1){
                    int k = heightSize - 1;
                    while(k > i && k - i > i - j){
                        if(height[k] >= height[i]){
                            //printf("%d * %d | ", height[i], k -i);
                            max = max > (height[i] * (k - i)) ? max : height[i] * (k - i);
                            break;
                        }
                        else{
                            k--;
                        }
                    }
                }
            }
        }
    }
    else{printf("new algo");
        for(int i = heightSize - 1; i >= 0 ; i--){
            if(height[i] == 0){
                continue;
            }
            if(i >= (heightSize - 1) / 2){
                int j = 0;
                while(j < i && (i - j) > max / height[i]){
                    if(height[j] >= height[i]){
                        max = max > (height[i] * (i - j)) ? max : height[i] * (i - j);
                        break;
                    }
                    else{
                        j++;
                    }
                }
                if(i - j < heightSize - i - 1){
                    int k = heightSize - 1;
                    while(k > i && k - i > i - j){
                        if(height[k] >= height[i]){
                            max = max > (height[i] * (k - i)) ? max : height[i] * (k - i);
                            break;
                        }
                        else{
                            k--;
                        }
                    }
                }
            }
            else{
                int j = heightSize - 1;
                while(j > i && ((j - i) > max / height[i])){//从右开始,找到高度大于i的第一个也是最远的j
                    if(height[j] >= height[i]){
                        //printf("%d * %d | ", height[i], j -i);
                        max = max > (height[i] * (j - i)) ? max : height[i] * (j - i);
                        break;
                    }
                    else{
                        j--;
                    }
                }
                if(j - i < i){//右端的距离小于左端最远的距离,则左端可能存在大于目前面积的列,检查左端
                    int k = 0;
                    while(k < i && i - k > j - i){
                        if(height[k] >= height[i]){
                            //printf("%d * %d | ", height[i], i-k);
                            max = max > (height[i] * (i - k)) ? max : height[i] * (i - k);
                            break;
                        }
                        else{
                            k++;
                        }
                    }
                }
            }
        }
    }


    return max;
}

观察测试用例,发现超时的用例要么是升序,要么是降序,因此,在最开始判断用例是升序还是降序,然后相应的遍历一次解决…
嗯,这是个投机取巧的方法,纯粹只是为了通过题目而已..
不过根据原来的算法,其实也才300ms左右,也算过了吧~哈哈
代码中我觉的有大量冗余的地方,但是懒得改了,就放在那里了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值