每日一题(14)Leetcode 135/42/13

今天第一次做hard题,并且做了两个,不出意外全都没能拿下。脑子里第一想法要么全都是暴力求解,要么即使知道是greedy,也想不出来具体怎么贪心。

1.leetcode135
第一种方法:Two-pass(也是我看到hint后采取的方法)

class Solution {
public:
    int candy(vector<int>& ratings) {
        int n=ratings.size();
        vector<int> candys(n,1);
        int sum=0;
        for(int i=1;i<n;i++){
            if(ratings[i]>ratings[i-1]){
                candys[i]=candys[i-1]+1;
            }
        }
        for(int i=n-2;i>-1;i--){
            if(ratings[i]>ratings[i+1]){
                candys[i]=max(candys[i],candys[i+1]+1);
            }
        }
        for(int i=0;i<n;i++){
            sum+=candys[i];
        }
        return sum;
    }
};

非常直观。第一遍pass确保所有的人都比左边拿到的candy多。第二遍pass确保所有人都比右边拿到的candy多。并且都是greedy的。
第二种方法:One-Pass

class Solution:
    def candy(self, ratings: List[int]) -> int:
        if not ratings:
            return 0
        
        ret, up, down, peak = 1, 0, 0, 0
        
        for prev, curr in zip(ratings[:-1], ratings[1:]):
            if prev < curr:
                up, down, peak = up + 1, 0, up + 1
                ret += 1 + up
            elif prev == curr:
                up = down = peak = 0
                ret += 1
            else:
                up, down = 0, down + 1
                ret += 1 + down - int(peak >= down)
        
        return ret

这个想法太amazing啦!up和down分别记录向上和向下走了多少步。每向上走一步,每次candy总数增加的数量就多1个(第一次增加1,第二次增加2这样)。如果是平的,根据规则,可以比前者少,那直接贪心,就给它设置成1,所以直加1。如果向下走,可以根据贪心,每次都把最新的那个设置成1,那为什么要加上down呢?比如连续的是3,2,1:遇到2的时候,3是1,这时需要把3加1,即3是2,2是1;遇到1的时候,需要把2加1,此时3又要加1,所以总共加2。为什么要减去int(peak>=down)呢?因为如果peak已经比down的总数都要大,此时不需要再加1了。

2.leetcode42
第一种方法:遍历两遍,找到左边最大和右边最大。

class Solution {
public:
    int trap(vector<int>& height) {
        int n=height.size();
        vector<int> left(n,0);
        vector<int> right(n,0);
        int max_left=0;
        int max_right=0;
        for(int i=1;i<n;i++){
            max_left=max(max_left,height[i-1]);
            left[i]=max_left;
        }
        for(int i=n-2;i>-1;i--){
            max_right=max(max_right,height[i+1]);
            right[i]=max_right;
        }
        int water=0;
        for(int i=1;i<n-1;i++){
            water+=max(min(left[i],right[i])-height[i],0);
        }
        return water;
    }
};

很直观,没什么可说的(虽然让我想一开始也想不出来)。
第二种方法:two pointers

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        int lmax = height[0];
        int rmax = height[n-1];
        int lpos = 1;
        int rpos = n-2;
        int water = 0;
        while(lpos <= rpos)
        {
            if(height[lpos] >= lmax)
            {
                lmax = height[lpos];
                lpos++;
            }
            else if(height[rpos] >= rmax)
            {
                rmax = height[rpos];
                rpos--;
            }
            else if(lmax <= rmax)
            {
                water += lmax - height[lpos];
                lpos++;
            }
            else
            {
                water += rmax - height[rpos];
                rpos--;
            }
        
        }
        return water;
    }
};

这个方法比较抽象,需要细细品味。
首先四个if为什么是用这种关系嵌套的?为什么不能调换?首先,如果出现height[lpos] >= lmax或者height[rpos] >= rmax,这说明这个位置必定存不住水,直接跳过并更新最大值即可。其次,如果不满足上述两个关系,则说明lpos处或者rpos处能存水了。此时就比lmax和rmax谁小谁大。如果lmax小,那么根据木桶效应,lpos处最大存水量能确定了。为什么rpos处没法确定?因为后续lmax有可能继续更新变大!rpos处同理。

3.leetcode13
这一题确实是easy的水平。

class Solution {
public:
    int romanToInt(string s) {
        int n=s.size();
        int max_=0;
        int cur=0;
        int INT=0;
        for(int i=n-1;i>=0;i--){
            if(s[i]=='I'){
                cur=1;
            }
            else if(s[i]=='V'){
                cur=5;
            }
            else if(s[i]=='X'){
                cur=10;
            }
            else if(s[i]=='L'){
                cur=50;
            }
            else if(s[i]=='C'){
                cur=100;
            }
            else if(s[i]=='D'){
                cur=500;
            }
            else if(s[i]=='M'){
                cur=1000;
            }
            if(cur>=max_){
                INT+=cur;
                max_=cur;
            }else{
                INT-=cur;
            }
        }
        return INT;
    }
};

一开始我为了避免比如8=IIX的情况出现,还从后往前算,但后来发现根本没有IIX这种,只有IX这种,所以从前往后算也行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值