【Leetcode】164. Maximum Gap

题目地址:

https://leetcode.com/problems/maximum-gap/

给定一个长 n n n数组 A A A,设其按从小到大排好序之后是 B B B,求 max ⁡ 1 ≤ i < n { B [ i ] − B [ i − 1 ] } \max_{1\le i< n}\{B[i]-B[i-1]\} max1i<n{B[i]B[i1]}。如果 n < 2 n<2 n<2则返回 0 0 0。题目保证 A [ i ] ≥ 0 A[i]\ge 0 A[i]0

A A A的最小值和最大值分别为 m , M m,M m,M,我们尝试将 ( m , M ] (m, M] (m,M]平均划分为若干个左开右闭的区间,然后想象一下将 A A A中的所有数都放进去。设最终答案是 y y y,则有 ( n − 1 ) y ≥ M − m (n-1)y\ge M-m (n1)yMm,即 y ≥ M − m n − 1 y\ge \frac{M-m}{n-1} yn1Mm,我们令平均划分的区间长度为 x x x,那么该区间中的 A A A的数的差值都是小于等于 x − 1 x-1 x1的,我们就取 x − 1 < M − m n − 1 x-1<\frac{M-m}{n-1} x1<n1Mm,那么得 x − 1 < y x-1<y x1<y,从而同一个区间内部的两个数的差不可能等于答案,从而 y y y只能是不同区间的数的差,我们只需枚举所有的后面一个区间的最小值减去前一个区间的最大值的差,然后找到最大的差即可。 x − 1 < M − m n − 1 ⇔ ( x − 1 ) ( n − 1 ) ≤ M − m − 1 ⇔ x ≤ ⌊ M − m + n − 2 n − 1 ⌋ x-1<\frac{M-m}{n-1}\Leftrightarrow (x-1)(n-1)\le M-m-1\\ \Leftrightarrow x\le \lfloor\frac{M-m+n-2}{n-1}\rfloor x1<n1Mm(x1)(n1)Mm1xn1Mm+n2所以我们只需要令 x = ⌊ M − m + n − 2 n − 1 ⌋ x=\lfloor\frac{M-m+n-2}{n-1}\rfloor x=n1Mm+n2即可。我们需要开 ⌈ M − m x ⌉ \lceil\frac{M-m}{x}\rceil xMm个区间。每个数 a a a属于的区间下标为 a − m − 1 x \frac{a-m-1}{x} xam1(除了 m m m自己,其不属于任何区间)。我们记录一下每个区间是否有 A A A中的数,同时存一下其最大和最小值,最后遍历一遍即可。代码如下:

class Solution {
 public:
  struct Range {
    int min, max;
    bool used;
  };

  int maximumGap(vector<int>& a) {
    int n = a.size();
    int m = INT_MAX, M = INT_MIN;
    for (int x : a) {
      m = min(m, x);
      M = max(M, x);
    }
    if (n < 2 || m == M) return 0;
	vector<Range> v((M - m + len - 1) / len, {INT_MAX, INT_MIN, false});
    int len = (M - m + n - 2) / (n - 1);
    for (int x : a) {
      if (x == m) continue;
      int k = (x - m - 1) / len;
      v[k] = {min(v[k].min, x), max(v[k].max, x), true};
    }

    int res = 0;
    for (int i = 0, prev = m; i < n - 1; i++)
      if (v[i].used) {
        res = max(res, v[i].min - prev);
        prev = v[i].max;
      }

    return res;
  }
};

时空复杂度 O ( n ) O(n) O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值