盛最多水的容器

盛最多水的容器

题目

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

来源:力扣(LeetCode)
题目序号:11
链接:https://leetcode.cn/problems/container-with-most-water

1

初始思路(堆空间存储装水的所有情况)

第一想法

看到题目,我的第一想法就是遍历,
事实上也肯定是要遍历的,
但遍历什么,遍历过程中要实现什么需要明确。

上面的遍历啥不清楚的话,可以先写一个框架,
然后往后看,
首先看向第一个元素,

如何装水&装水数

因为是要装水的,
根据“木桶效应”,最低的板子决定了装水量,
所以需要判断第一个元素参与了的“木桶”可以装多少水,然后再进行下一步比较,

所以,遍历啥已经很清楚了,
以当前的第一个元素为研究对象的话,就需要判断他和其他元素的大小,
毕竟,对于当前的第一块木板,只有找到一块比它长或者一样长的木板,才能装水,
对于有序数组的话,直接选择排序往后就OK,
很可惜,这里是无序的,所以需要考虑的事情就有点多,

需要考虑的有两点,
一是遍历的顺序,这个其实对于我们来说啥都不是,因为我们习惯性的向右
二是木桶的形状,是左右一样高?还是左高右低?或者说左低右高,
第二点说的明白点,就是如果现在使用选择排序,在遍历取得装水数的时候让第二个for里面的j初始值为i+1,就会出问题:

1

看见没,很明显的,装水数咋说也不可能这么短吧。

所以说,若想将三种木桶全部考虑到,这个j的初始值必须要为0:

1

对于上图出现的装水数,题目中已经给了计算方法了:
对于有装水机会的,
找出比他大的数,然后比对下标,算出差值,
然后用这个差值乘以当前元素,就得到了装水数

处理所得的装水数

解决了各种装水的问题,然后就是需要对这些数据进行处理了,

很明显,这些装水的数都是int类型的数,
我们很容易想到可以设一个int类型的数组来装他们,

但是还是会遇到一个问题,那就是数组的长度问题,
这里可以尽量给大一点,
若是实在纠结给多少长度的话,可以试试将这些数据存在堆空间里面,这样一来,这就是一个很实用的变长数组了,

将遍历过程中每个元素得到的装水数,单独存在一个堆空间数组里面
然后在那个新构成的堆空间数组里面寻找最大值,将其返回就行了

初始代码

#include <stdio.h>
#include <strings.h>
#include <stdlib.h>

int WATER(int *p, int len)
{
    // 遍历
    // 判断每一个元素是不是最大的,不是最大就有装水的机会
    // 对于有装水机会的,找出比他大的数,然后比对下标,算出差值,然后用这个差值乘以当前元素
    // 将遍历过程中每个元素得到的装水数单独存在一个堆空间数组里面
    // 然后在那个新构成的数组里面寻找最大值,并返回
    
    int x = 0, y = 0;

    // 将所有装水的情况写入堆空间
    int *q = (int *)malloc(sizeof(int)*len*len);
    bzero(q, sizeof(int)*len*len);
    for (int i = 0; i < len; i++)
    {

        for (int j = 0; j < len; j++)
        {

            if (p[i]<=p[j])
            {
                ++y; // 记录堆空间中元素的个数
                int a = j-i;
                int b = abs(a*p[i]);
                q[x++] = b;
            }
            
        }
        
    }

    // 将堆空间的数据从大到小排列,如此一来,只需要返回第一个值就行了
    int a = 0;
    for (int i = 0; i < y; i++)
    {
        for (int j = i+1; j < y; j++)
        {
            if (q[i]<q[j])
            {
                a = q[i];
                q[i] = q[j];
                q[j] = a;
            }  
        }
    }

    return q[0];
    
}

int main(int argc, char const *argv[])
{
    int height[] = {1, 8, 6, 2, 5, 4, 8, 3, 7};
    int *p = height;
    int len = sizeof(height)/4; // 求出元素的个数
    int a = WATER(p, len);

    printf("water:\t%d\n", a);

    return 0;
}

1

自我修改

以上的内容都是我自己写的,
可能是由于太低效,在力扣上提交失败,
1

可以看到,当实验的结果有很多,我存在堆空间中的数据就太大了,有len*len个,
可能正是因为这个,拖慢了我的程序运行速度,甚至出错,
但是程序本身是没有问题的,
用堆空间的这个思路遇到这种情况,进而导致这样的结果,应该是必然的事情

1
1

所以,这里在堆空间存所有情况思路之上,优化修改代码的空间,真的不大

堆空间都不行,数组就别想了

力扣上的参考解答

看到了一个很厉害的解答,可以说很完美了,
没用堆空间,而是不断更新最大装水数,
而且运用了头尾双指针,很大程度上减少了无必要的循环次数

关于这个头尾双指针,就是从头尾分别向对侧遍历,
在每次循环中,头尾指针中的某一个满足条件就会移动,
所以,当破开循环条件后,所有的情况其实已经考虑到了,

所以,每遭遇一种情况,就计算出装水数,并与上一次的进行比较,
保留最大的,一直到所有情况比较完,
这样到最后,保留的一定是最大的容量

这是大佬本人的解释:
1

int maxArea(int* height, int heightSize){
    int start = 0;
    int end = heightSize - 1;
    int max;
    int tmp;

    max = (end - start) * (height[start] > height[end] ? height[end] : height[start]);
    while (end > start) {
        tmp = (end - start) * (height[start] > height[end] ? height[end] : height[start]);
        max = tmp > max ? tmp : max;
        if (height[start] < height[end]) {
            start++;
        } else if (height[start] > height[end]){
            end--;
        } else {
            start++;
            end--;
        }
    }

    return max;
}

将这个函数代替我的函数用到刚刚把我堆空间炸掉的地方:
1

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值