LeetCode11 Container With Most Water / LeetCode55 Jump Game 总结

LeetCode11 Container With Most Water

题目描述

You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]).

Find two lines that together with the x-axis form a container, such that the container contains the most water.

Return the maximum amount of water a container can store.

Notice that you may not slant the container.

输入样例1

Input: height = [1,8,6,2,5,4,8,3,7]
Output: 49
Explanation: The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.

在这里插入图片描述

输入样例2

Input: height = [1,1]
Output: 1

数据范围
n == height.length
2 <= n <= 105
0 <= height[i] <= 104

题目分析

力扣把这道题归在贪心里,但好像更多的是双指针算法…
在开始没有看解析之前,也想到了双指针算法,左指针i从第一个line开始向右移动,右指针r从最后一个line开始向左移动。我们假定i先开始移动,如果lines[i+1]的值会比 min(line[i],line[j])都小,那么就跳过这个line,因为该line形成的容器,即没有当前的容器高,两个line的距离也更短。当更新了res之后,我们换另一边。最后当i=j时我们结束算法。

例如对于输入样例1:height = [1,8,6,2,5,4,8,3,7],初始时i=0,j=8,由于8>1且8>7,我们需要更新res(记录最大的体积),此时i=1,j=8。我们再移动右指针,由于3<7且3<8,所以j- -。再往前移动。

但是我们可以发现,我们在第一次移动i的时候,好像就舍弃了1和除了line[8]之外的所有组合了。万一中间存在一个值很大的line,它们的距离又足够远,是最优解呢?所以当时就认为好像不太行,就没有再细想了。

但事实上,在i=0,j=8时,我们让i++,略过i=0,j=[1:7]是正确的!因为在题目的情景下,容器的高取决于更小的一端。当1≤j≤7时:
1.line[j]≥line[8],但由于line[1]<line[8],所以更大也没有用,容器的容量取决于line[1],最大值不会发生变化。
2.line[j]≤line[8],那就更不要考虑了,容器的高不会增加,且两端的距离更小了,最大值也不会发生变化。

因而,我们就是可以执行i++,但是我们不可以执行j- -,这是不等价的。因为line[j]是等大的一端,line[i]可以增大,有机会求得更大容积。

所以在这里,双指针算法,指针移动的规则为:总是移动值更小的一端,更新当前容积最大值,直到i=j

代码实现

class Solution {
public:
    int maxArea(vector<int>& height) {
        int left=0;
        int right=height.size()-1;
        int res=0;
        while(left<right){
            int v = (right-left)*min(height[left],height[right]);
            if(v>res) res=v;
            if(height[left]<height[right]) left++;
            else right--;
        }
        return res;
    }
};

LeetCode55 Jump Game

题目描述

You are given an integer array nums. You are initially positioned at the array’s first index, and each element in the array represents your maximum jump length at that position.

Return true if you can reach the last index, or false otherwise.

输入样例1

Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.

输入样例2

Input: nums = [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.

数据范围
1 <= nums.length <= 104
0 <= nums[i] <= 105

题目分析

LeetCode还是把它归为贪心算法…事实上,拿到这一题,最开始的想法是树的遍历,因为数组中的每一个元素,都可以看成一个节点,其可以跳转到的地方,就是其子节点。例如我们用广度优先搜索策略,用数组模拟队列,就可以写出如下的代码:

class Solution {
public:
    bool canJump(vector<int>& nums) {
        //那这个不是一个树的遍历的题吗...
        //数据结构:队列,广度优先遍历
        int len = nums.size()-1;
        if(len==0) return true;
        int q[200010];
        int str[100010];//是否被遍历过
        memset(str,0,sizeof str);//没有被遍历过,是0
        int head = 0,tail=0;
        q[tail++]=0;//将初始节点放入
        str[0]=1;
        while(head<tail){//还可以遍历得下去
            int e = q[head++];//取出具体的数字的下标
            //cout<<e<<" "<<str[e]<<endl;
            for(int i = 1;i<=nums[e];i++){//可以取1-nums[i],存的是下标
                if(e+i<len && !str[e+i]){
                    q[tail++]=e+i;//存入下标
                    str[e+i]=1;
                }
                else{
                    if(e+i==len) return true;//到达终点
                }
            }
        }
        return false;
    }
};

我们用str数组来记录是否遍历过该节点,没有被遍历过的元素我们才将其加入队列中。
那最后其实这么做,时间复杂度和空间复杂度都很高。
在这里插入图片描述
那LeetCode官方给出的一个题解是,我们维护一个可以到达的最远的地方x,一旦判断出x≥nums.size()-1(也就是最后一个元素的下标)时,就返回true

什么意思呢?对于数组中下标为i的元素nums[i],若其是可达的,那么i,i+1,i+2,…,i+nums[i]都是可以到达的。所以我们再去依次检查i+1,i+2,……,i+nums[i]这些元素,根据其nums[i]的值,去更新可以到达的下标的值,如果发现x≥nums.size()-1,那么是可以到达最后一个元素的。当然了,存在一种情况为,我们已经在检查nums[x]了,但是nums[x]=0,x就没有办法继续进行更新了,所以对于代码实现,我们只要在for循环体中,判断条件加上i<=x,一旦退出循环,就可以返回false。

代码实现

class Solution {
public:
    bool canJump(vector<int>& nums) {
        //我们维护可以到达的最远的位置x
        //遍历数组所有的元素,当然其要小于x
        int x = 0;
        int len = nums.size();
        for(int i = 0 ;i<=x;i++){
            x=max(x,i+nums[i]);
            if(x>=len-1) return true;
        }
        return false;
    }
};

所以贪心是起到一个什么作用呢。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值