leetcode135 两次遍历消除局部限制

解法一:一次遍历
操作稍显复杂,细节多,暂不讨论。

解法二:两次遍历

证明:两次遍历可行
对任意一个元素,一共三种情况,

  • 两边都比自己大
  • 两边都比自己小
  • 一边大一边小

对于第一种情况,此处元素值一定为1,求max后依然满足。
对于第二种情况,两边都小,求max后仍然满足。
对于第三种情况,求max后一定还满足比自己小的那边,但是否还满足比自己大的那边呢?
答案是肯定的,因为在其中一次遍历中,比自己大的那边一定等于max后的值+1,所以满足。
综上,两次遍历是保证正确的。

以下文字可忽略
数据结构:一个左满意数组,右满意数组
左满意数组第i个位置:对自己左边的安排满意的糖数

此题最重要的点是,一个点多高,取决于左右相邻的元素。当我们从左向右遍历时,每个点都是一定满足左条件的,如果小于就为1.如果前面的元素已经为1,这个点也为1,但这样其实不满足左条件,因为至少有一颗糖。此时的关键在于 ,对于这颗糖,肯定是1了,不可能为2。他是完全ok的,毕竟自己小,他不会不满意。所以问题的关键在他左边那颗糖,他会不满意。但左边那颗糖是完全满足左条件的,所以也ok。这样下来,所有点对自己都是满意的。
遍历两遍,每个点取最大,必然对两边都是满意的。有一个问题就是,本来有一个点,对自己右边是满意的,但右边突然变大了,这样会不会不满意?这种是不可能的,如果不满意,说明左边比右边的大,但如果左边比右边大,那在右向左过程中,肯定会比他多1,故没有问题。

class Solution {
public:
    int candy(vector<int>& ratings) {
        int n = ratings.size();
        vector<int> left(n, 1), right(n, 1);

        for(int i=1;i<n;i++)
        {
            if(ratings[i] > ratings[i-1])left[i] = left[i-1]+1;
        }

        for(int i=n-2;i>=0;i--)
        {
            if(ratings[i] > ratings[i+1])right[i] = right[i+1]+1;
        }

        int ret = 0;
        for(int i=0;i<n;i++)ret += max(left[i], right[i]);

        return ret;
    }
};

空间优化:右数组可以直接在左满意数组上操作,就不需要额外的 O ( N ) O(N) O(N)空间了。

class Solution {
public:
    int candy(vector<int>& ratings) {
        int n = ratings.size();
        vector<int> left(n, 1);

        for(int i=1;i<n;i++)
        {
            if(ratings[i] > ratings[i-1])left[i] = left[i-1]+1;
        }

        int ret = left[n-1];
        for(int i=n-2;i>=0;i--)
        {
            if(ratings[i] > ratings[i+1])left[i] = max(left[i], left[i+1]+1);
            ret += left[i];
        }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值