leetcode825. 适龄的朋友

Posted 2021dragon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode825. 适龄的朋友相关的知识,希望对你有一定的参考价值。

LeetCode系列文章

文章目录

一、题目描述

  在社交媒体网站上有 n n n 个用户。给你一个整数数组 a g e s ages ages,其中 a g e s [ i ] ( 1 ≤ a g e s [ i ] ≤ 120 ) ages[i](1\\leq ages[i] \\leq 120) ages[i](1ages[i]120) 是第 i i i 个用户的年龄。

  如果下述任意一个条件为真,那么用户 x x x 将不会向用户 y y y 发送好友请求:

  • a g e s [ y ] ≤ 0.5 × a g e s [ x ] + 7 ages[y]\\leq0.5\\times ages[x]+7 ages[y]0.5×ages[x]+7
  • a g e s [ y ] > a g e s [ x ] ages[y]>ages[x] ages[y]>ages[x]
  • a g e s [ y ] > 100 & & a g e s [ x ] < 100 ages[y]>100\\&\\&ages[x]<100 ages[y]>100&&ages[x]<100

  否则, x x x 将会向 y y y 发送一条好友请求。

  注意,如果 x x x y y y 发送一条好友请求, y y y 不必也向 x x x 发送一条好友请求。另外,用户不会向自己发送好友请求。

  返回在该社交媒体网站上产生的好友请求总数。

二、示例

  输入: ages = [16, 16]
  输出: 2

  解释: 2人互发好友请求。

三、主体思路

1、暴力解法

  采用暴力解法解决该题目是非常简单的,要判断一个用户能够给哪些用户发送好友请求,只需要遍历这 n − 1 n-1 n1(不包括自己)个用户,依次判断是否满足发送好友请求的条件即可。

  很明显这种暴力解法的时间复杂度是 O ( N 2 ) O(N^2) O(N2),当用户数据量过大时计算消耗的时间就会暴增,因此这种解法是不推荐的。

2、排序+双指针

  仔细观察题目所给的三个条件,你会发现条件三其实是蕴含在条件二当中的,如果满足了条件三那就一定满足条件二,因此只要不满足前两个条件,那么用户 x x x 就能向用户 y y y 发送好友请求,也就是用户 y y y 需要满足: 0.5 × a g e s [ x ] + 7 < a g e s [ y ] ≤ a g e s [ x ] 0.5\\times ages[x]+7<ages[y]\\leq ages[x] 0.5×ages[x]+7<ages[y]ages[x]

将这个关系用数轴表示如下:

  如果存在满足要求的用户 y y y,那么 0.5 × x + 7 < x 0.5\\times x+7<x 0.5×x+7<x,即 x > 14 x > 14 x>14。也就是说,如果一个用户的年龄小于等于14,那么该用户将不能向任何用户发送好友请求。

  现在看来,要知道用户 x x x 能够向哪些用户 y y y 发送好友请求,实际就需要求出该数轴上对应的左右边界,年龄位于该区域内的用户就是用户 x x x 能够向其发送好友请求的用户。

  在寻找左右边界时可以用 l e f t left left r i g h t right right 表示左右边界的下标(双指针),如果左右都采用闭区间,即 l e f t left left 指向的是第一个满足要求的用户, r i g h t right right 指向的是最后一个满足要求的用户,那么最终 r i g h t − l e f t right-left rightleft 的值就是满足要求的用户 y y y 的个数。(注意:这里不是 r i g h t − l e f t + 1 right-left+1 rightleft+1,因为用户 x x x 本身也是在该区域当中的,但用户 x x x 不会向自己发送好友请求)

因此解题步骤如下:

  • 对所给 n n n 个用户的年龄进行排序。
  • 依次遍历这 n n n 个用户的年龄。
  • 在遍历用户时,如果该用户的年龄小于等于14,则该用户能够向外发送好友请求的个数为0;如果该用户的年龄大于14,则通过双指针找到满足发送要求的区域,进而得出该用户能够向外发送的好友请求的个数。
  • 最后将每个用户能够向外发送的好友请求的个数进行累加即可。

  特别注意,在通过双指针确定满足要求的年龄区域时,只有第一次需要在 n n n 个用户的基础上从头进行查找。而后续在确定区域时,区域的左右边界只需要在上一个用户的左右边界的基础上向后进行查找即可。因为 0.5 × x + 7 0.5\\times x+7 0.5×x+7 x x x 是线性的关系,当 x x x 增大时, 0.5 × x + 7 0.5\\times x+7 0.5×x+7 的值也会增大,因此我们无需再判断上一个用户的 l e f t left left 指针之前的用户年龄是否在本次限定的区域当中。

3、计数排序+前缀和

  仔细观察你会发现题目给定用户的年龄是在 [ 1 , 120 ] [1, 120] [1,120] 范围内的,因此我们可以采用计数排序统计各个年龄段用户的个数并进行排序。

  比如我们将排序结果存储到 c n t cnt cnt 数组当中,此时 c n t [ a g e ] cnt[age] cnt[age] 就表示年龄为 a g e age age 的用户个数,而每一个年龄为 a g e age age 的用户能够向外发送的好友请求的数量就是: ( ∑ i = 0.5 × a g e + 8 a g e c n t [ i ] ) − 1 (\\sum_i=0.5\\times age+8^agecnt[i])-1 (i=0.5×age+8agecnt[i])1,其中减一是因为用户不会向自己发送好友请求。

  为了避免每次都要遍历 c n t cnt cnt 数组进行求和,我们可以计算出 c n t cnt cnt 数组的前缀和数组 p r e pre pre p r e [ a g e ] pre[age] pre[age] 代表的就是年龄段位于1 ~ age的用户个数: p r e [ a g e ] = ∑ i = 1 a g e c n t [ i ] pre[age]=\\sum_i=1^agecnt[i] pre[age]=i=1agecnt[i]

  此时每一个年龄为 a g e age age 的用户能够向外发送的好友请求的数量就可以写为: p r e [ a g e ] − p r e [ 0.5 × a g e + 7 ] − 1 pre[age]-pre[0.5\\times age+7]-1 pre[age]pre[0.5×age+7]1

  此时我们就能够在 O ( 1 ) O(1) O(1) 的时间内计算出一个年龄为 a g e age age 的用户能够向外发送的好友请求的数量,将该值乘以 c n t [ a g e ] cnt[age] cnt[age] 就是该年龄段的所有用户总计能够向外发送的好友请求的数量。

因此解题步骤如下:

  • 通过计数排序统计每个年龄段的用户个数。
  • 计数出 c n t cnt cnt 数组的前缀和数组 p r e pre pre
  • 通过 ( p r e [ a g e ] − p r e [ 0.5 × a g e + 7 ] − 1 ) × c n t [ a g e ] (pre[age]-pre[0.5\\times age+7]-1)\\times cnt[age] (pre[age]pre[0.5×age+7]1)×cnt[age] 公式计算出每个年龄段的用户总计能够向外发送的好友请求的数量,将其进行累加就是最终结果。

四、代码实现

1、暴力解法

2、排序+双指针

3、计数排序+前缀和

以上是关于leetcode825. 适龄的朋友的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 825 适龄的朋友[前缀和] HERODING的LeetCode之路

LeetCode 1609. 奇偶树 / 1078. Bigram 分词 / 825. 适龄的朋友(计数排序)

LeetCode 1609. 奇偶树 / 1078. Bigram 分词 / 825. 适龄的朋友(计数排序)

《LeetCode之每日一题》:248.适龄的朋友

LeetCode 825. Friends Of Appropriate Ages

校门外的树(三种解法,非直接暴力)