力扣面试150题(3)

一、跳跃游戏Ⅱ

给你一个非负整数数组 nums ,你最初位于数组的第一个位置。数组中的每个元素代表你在该位置可以跳跃的最大长度。你的目标是使用最少的跳跃次数到达数组的最后一个位置。假设你总是可以到达数组的最后一个位置。

提示:

  1. 1 <= nums.length <= 10^4
  2. 0 <= nums[i] <= 1000

示例 1:

输入: nums = [2,3,1,1,4]

输出: 2

解释: 跳到最后一个位置的最小跳跃数是 2。

     从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

从左到右(贪心)

我们需要尽可能少的跳跃,那么则需要尽可能大的跳跃,如果一个起跳点的跳跃格子为3,那么后面3个格子都可以作为下一个起跳点,我们需要选择这三个格子中跳的最远的格子(贪心)

#include<iostream>  

#include<vector>  

using namespace std;  

  

int jump(vector<int>& nums);   

int main(){  

    int n;  

    cout<<"输入数组个数:";   

    cin>>n;  

    vector<int >nums(n);  

    cout<<"输入跳跃的步数:";  

    for(int i=0;i<n;i++){  

        cin>>nums[i];  

    }  

    cout<<"需要"<<jump(nums)<<"步";  

    return 0;  

}   

int jump(vector<int>& nums) {  

    int n=nums.size();  

    int ans=0;  

    int start=0,end=1;  

    while(end<n){  

        int maxPos=0;  

        //找到最大   

        for(int i=start;i<end;i++){  

            maxPos=max(maxPos,nums[i]+i);  

        }  

        //下一次起跳开始是这一次起跳的结束   

        start=end;  

        //下一次起跳结束是这一次能跳到最大的范围   

        end=maxPos+1;  

        //步数+1   

        ans++;  

    }   

    return ans;  

}  

从右到左(贪心)

找离终点最远的格子(即从头开始遍历,首先能到达终点的格子)

我们知道最终要到达最后一个位置,然后我们找前一个位置,遍历数组,找到能到达它的位置,离它最远的就是要找的位置。然后继续找上上个位置,最后到了第 0 个位置就结束了。

至于离它最远的位置,其实我们从左到右遍历数组,第一个满足的位置就是我们要找的。

#include<iostream>  

#include<vector>  

using namespace std;  

  

int jump(vector<int>& nums);   

int main(){  

    int n;  

    cout<<"输入数组个数:";   

    cin>>n;  

    vector<int >nums(n);  

    cout<<"输入跳跃的步数:";  

    for(int i=0;i<n;i++){  

        cin>>nums[i];  

    }  

    cout<<"需要"<<jump(nums)<<"步";  

    return 0;  

}   

int jump(vector<int>& nums) {  

    int n=nums.size();  

    int ans=0;  

    int pos=n-1;  

    while(pos!=0){  

        //找到能到达pos的最小下标   

        for(int i=0;i<pos;i++){  

            if(nums[i]+i>=pos){  

                pos=i;  

                ans++;  

                break;  

            }  

        }  

    }   

    return ans;  

}  

二、接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

提示:

  1. n == height.length
  2. 1 <= n <= 2 * 10^4
  3. 0 <= height[i] <= 10^5

示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]

输出:6

解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

按行计算(超出时间限制)

整个思路就是,求第 i 层的水,遍历每个位置,如果当前的高度小于 i,并且两边有高度大于等于 i 的,说明这个地方一定有水,水就可以加 1。

如果求高度为 i 的水,首先用一个变量 temp 保存当前累积的水,初始化为 0。从左到右遍历墙的高度,遇到高度大于等于 i 的时候,开始更新 temp。更新原则是遇到高度小于 i 的就把 temp 加 1,遇到高度大于等于 i 的,就把 temp 加到最终的答案 ans 里,并且 temp 置零,然后继续循环。

具体看代码:

int trap(vector<int>& height) {  

    int ans=0;  

    int maxH=INT_MIN;  

    //找到最大高度   

    for(int i=0;i<height.size();i++){  

        maxH=max(maxH,height[i]);  

    }  

    //只要小于,数组之前的都要加1   

    vector<vector<int>>h(maxH+1);  

    for(int i=0;i<height.size();i++){  

        int temp=height[i];  

        for(int j=1;j<=temp;j++)h[j].push_back(i);  

    }  

    //一行一行来计算   

    for(int i=1;i<=maxH;i++){  

        int m=h[i].size();  

        int left=h[i][0];  

        int right=h[i][m-1];  

        ans+=right-left+1-m;  

    }  

    return ans;  

}  

按列计算(超出时间限制)

求每一列的水,我们只需要关注当前列,以及左边最高的墙,右边最高的墙就够了。

装水的多少,当然根据木桶效应,我们只需要看左边最高的墙右边最高的墙较矮的一个就够了。

按列计算+动态规划

解法二中。对于每一列,我们求它左边最高的墙和右边最高的墙,都是重新遍历一遍所有高度,这里我们可以优化一下。

首先用两个数组,max_left [i] 代表第 i 列左边最高的墙的高度,max_right[i] 代表第 i 列右边最高的墙的高度。(一定要注意下,第 i 列左(右)边最高的墙,是不包括自身的,和 leetcode 上边的讲的有些不同)

对于 max_left我们其实可以这样求。

max_left [i] = Max(max_left [i-1],height[i-1])。它前边的墙的左边的最高高度和它前边的墙的高度选一个较大的,就是当前列左边最高的墙了。

对于 max_right我们可以这样求。

max_right[i] = Max(max_right[i+1],height[i+1]) 。它后边的墙的右边的最高高度和它后边的墙的高度选一个较大的,就是当前列右边最高的墙了。

int trap(vector<int>& height) {  

    int ans=0;  

    int n=height.size();  

    //保留左边最大   

    vector<int>left(n);  

    //保留右边最大   

    vector<int>right(n) ;  

    for(int i=1;i<n-1;i++){  

        left[i]=max(left[i-1],height[i-1]);  

    }  

    for(int i=n-2;i>=0;i--){  

        right[i]=max(right[i+1],height[i+1]);  

    }  

    //计算接水量   

    for(int i=1;i<height.size();i++){  

          

        int res=min(left[i],right[i]);  

        ans+=(res-height[i])>0?res-height[i]:0;  

    }   

    return ans;  

} 

  1. 按行计算(超出时间限制)
  1. #include<iostream>  
  2. #include<vector>  
  3. using namespace std;  
  4.   
  5. int trap(vector<int>& height);  
  6. int main(){  
  7.     int n;  
  8.     cout<<"柱子个数:";  
  9.     cin>>n;   
  10.     vector<int>height(n);  
  11.     cout<<"输入柱子高度:";  
  12.     for(int i=0;i<n;i++){  
  13.         cin>>height[i];  
  14.     }   
  15.     cout<<"能接到的雨水为:"<<trap(height);  
  16.     return 0;  
  17. }   
  18. int trap(vector<int>& height) {  
  19.     int ans=0;  
  20.     int maxH=INT_MIN;  
  21.     //找到最大高度   
  22.     for(int i=0;i<height.size();i++){  
  23.         maxH=max(maxH,height[i]);  
  24.     }  
  25.     //只要小于,数组之前的都要加1   
  26.     vector<vector<int>>h(maxH+1);  
  27.     for(int i=0;i<height.size();i++){  
  28.         int temp=height[i];  
  29.         for(int j=1;j<=temp;j++)h[j].push_back(i);  
  30.     }  
  31.     //一行一行来计算   
  32.     for(int i=1;i<=maxH;i++){  
  33.         int m=h[i].size();  
  34.         int left=h[i][0];  
  35.         int right=h[i][m-1];  
  36.         ans+=right-left+1-m;  
  37.     }  
  38.     return ans;  
  39. }  

  1. 按列计算(超出时间限制)
  1. #include<iostream>  
  2. #include<vector>  
  3. using namespace std;  
  4.   
  5. int trap(vector<int>& height);  
  6. int main(){  
  7.     int n;  
  8.     cout<<"柱子个数:";  
  9.     cin>>n;   
  10.     vector<int>height(n);  
  11.     cout<<"输入柱子高度:";  
  12.     for(int i=0;i<n;i++){  
  13.         cin>>height[i];  
  14.     }   
  15.     cout<<"能接到的雨水为:"<<trap(height);  
  16.     return 0;  
  17. }   
  18. int trap(vector<int>& height) {  
  19.     int ans=0;  
  20.     for(int i=1;i<height.size();i++){  
  21.         int left=0;  
  22.         //找左边的最大值   
  23.         for(int l=i-1;l>=0;l--){  
  24.             left=max(left,height[l]);  
  25.         }  
  26.         int right=0;  
  27.         //找右边的最大值   
  28.         for(int r=i+1;r<height.size();r++){  
  29.             right=max(right,height[r]);  
  30.         }  
  31.         int res=min(left,right);  
  32.         if(res>height[i])ans+=res-height[i];  
  33.     }   
  34.     return ans;  
  35.  

  1. 按列计算+动态规划
  1. #include<iostream>  
  2. #include<vector>  
  3. using namespace std;  
  4.   
  5. int trap(vector<int>& height);  
  6. int main(){  
  7.     int n;  
  8.     cout<<"柱子个数:";  
  9.     cin>>n;   
  10.     vector<int>height(n);  
  11.     cout<<"输入柱子高度:";  
  12.     for(int i=0;i<n;i++){  
  13.         cin>>height[i];  
  14.     }   
  15.     cout<<"能接到的雨水为:"<<trap(height);  
  16.     return 0;  
  17. }   
  18. int trap(vector<int>& height) {  
  19.     int ans=0;  
  20.     int n=height.size();  
  21.     //保留左边最大   
  22.     vector<int>left(n);  
  23.     //保留右边最大   
  24.     vector<int>right(n) ;  
  25.     for(int i=1;i<n-1;i++){  
  26.         left[i]=max(left[i-1],height[i-1]);  
  27.     }  
  28.     for(int i=n-2;i>=0;i--){  
  29.         right[i]=max(right[i+1],height[i+1]);  
  30.     }  
  31.     //计算接水量   
  32.     for(int i=1;i<height.size();i++){  
  33.           
  34.         int res=min(left[i],right[i]);  
  35.         ans+=(res-height[i])>0?res-height[i]:0;  
  36.     }   
  37.     return ans;  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值