|
| 1 | +--- |
| 2 | +title: 825.适龄的朋友 |
| 3 | +date: 2024-11-17 18:11:16 |
| 4 | +tags: [题解, LeetCode, 中等, 数组, 双指针, 二分查找, 排序] |
| 5 | +--- |
| 6 | + |
| 7 | +# 【LetMeFly】825.适龄的朋友:双指针(排序nlog n) 或 桶排序(n + C^2) |
| 8 | + |
| 9 | +力扣题目链接:[https://leetcode.cn/problems/friends-of-appropriate-ages/](https://leetcode.cn/problems/friends-of-appropriate-ages/) |
| 10 | + |
| 11 | +<p>在社交媒体网站上有 <code>n</code> 个用户。给你一个整数数组 <code>ages</code> ,其中 <code>ages[i]</code> 是第 <code>i</code> 个用户的年龄。</p> |
| 12 | + |
| 13 | +<p>如果下述任意一个条件为真,那么用户 <code>x</code> 将不会向用户 <code>y</code>(<code>x != y</code>)发送好友请求:</p> |
| 14 | + |
| 15 | +<ul> |
| 16 | + <li><code>ages[y] <= 0.5 * ages[x] + 7</code></li> |
| 17 | + <li><code>ages[y] > ages[x]</code></li> |
| 18 | + <li><code>ages[y] > 100 && ages[x] < 100</code></li> |
| 19 | +</ul> |
| 20 | + |
| 21 | +<p>否则,<code>x</code> 将会向 <code>y</code> 发送一条好友请求。</p> |
| 22 | + |
| 23 | +<p>注意,如果 <code>x</code> 向 <code>y</code> 发送一条好友请求,<code>y</code> 不必也向 <code>x</code> 发送一条好友请求。另外,用户不会向自己发送好友请求。</p> |
| 24 | + |
| 25 | +<p>返回在该社交媒体网站上产生的好友请求总数。</p> |
| 26 | + |
| 27 | +<p> </p> |
| 28 | + |
| 29 | +<p><strong>示例 1:</strong></p> |
| 30 | + |
| 31 | +<pre> |
| 32 | +<strong>输入:</strong>ages = [16,16] |
| 33 | +<strong>输出:</strong>2 |
| 34 | +<strong>解释:</strong>2 人互发好友请求。 |
| 35 | +</pre> |
| 36 | + |
| 37 | +<p><strong>示例 2:</strong></p> |
| 38 | + |
| 39 | +<pre> |
| 40 | +<strong>输入:</strong>ages = [16,17,18] |
| 41 | +<strong>输出:</strong>2 |
| 42 | +<strong>解释:</strong>产生的好友请求为 17 -> 16 ,18 -> 17 。 |
| 43 | +</pre> |
| 44 | + |
| 45 | +<p><strong>示例 3:</strong></p> |
| 46 | + |
| 47 | +<pre> |
| 48 | +<strong>输入:</strong>ages = [20,30,100,110,120] |
| 49 | +<strong>输出:</strong>3 |
| 50 | +<strong>解释:</strong>产生的好友请求为 110 -> 100 ,120 -> 110 ,120 -> 100 。 |
| 51 | +</pre> |
| 52 | + |
| 53 | +<p> </p> |
| 54 | + |
| 55 | +<p><strong>提示:</strong></p> |
| 56 | + |
| 57 | +<ul> |
| 58 | + <li><code>n == ages.length</code></li> |
| 59 | + <li><code>1 <= n <= 2 * 10<sup>4</sup></code></li> |
| 60 | + <li><code>1 <= ages[i] <= 120</code></li> |
| 61 | +</ul> |
| 62 | + |
| 63 | + |
| 64 | + |
| 65 | +## 方法一:双指针 |
| 66 | + |
| 67 | +如果满足第三条`ages[y] > 100 && ages[x] < 100`,那么一定满足第二条`ages[y] > ages[x]`,因此第三条可以忽略(只要满足第二条,不需要看是否满足第三条就一定不会受到邀请)。 |
| 68 | + |
| 69 | +由第一条和第二条可知,当`y`满足`0.5x+7 < y <= x`时`y`才会收到来自`x`的邀请。由`0.5x+7 < x`可得只有`>= 15`的`x`才会有可能发送邀请。 |
| 70 | + |
| 71 | +对于邀请发送者`x`,`y`的最小值需要满足`y > 0.5x+7`,`y`的最大值需要满足`y <= x`。 |
| 72 | + |
| 73 | +假设`y_l`是第一个满足`> 0.5x+7`的`y`下标,`y_r`是最后一个满足`<= x`的`y`下标,那么对于区间`[y_l, y_r]`,只有`x`自身不会收到`x`的邀请,其他用户都会收到`x`的邀请。因此`x`的邀请发送数量为`区间长度 - 1 = y_r - y_l`。 |
| 74 | + |
| 75 | +不难发现随着`x`的非递减,`y`区间的左右端点`y_l`和`y_r`也是非递减的,因此就可以使用双指针来实现每个元素只被遍历数次。 |
| 76 | + |
| 77 | ++ 时间复杂度$O(n\log n)$:排序时间复杂度$O(n\log n)$,双指针时间复杂度$O(n)$ |
| 78 | ++ 空间复杂度$O(\log n)$ |
| 79 | + |
| 80 | +### AC代码 |
| 81 | + |
| 82 | +#### C++ |
| 83 | + |
| 84 | +```cpp |
| 85 | +/* |
| 86 | + * @Author: LetMeFly |
| 87 | + * @Date: 2024-11-17 17:39:44 |
| 88 | + * @LastEditors: LetMeFly.xyz |
| 89 | + * @LastEditTime: 2024-11-17 18:11:18 |
| 90 | + */ |
| 91 | +/* |
| 92 | +对于x:x要加: |
| 93 | +0.5x+7 < y <= x |
| 94 | +x + 7 < 2y |
| 95 | +也就是说 |
| 96 | +0.5x+7 < x 可得 x>14 才能有朋友 |
| 97 | +*/ |
| 98 | +class Solution { |
| 99 | +public: |
| 100 | + int numFriendRequests(vector<int>& ages) { |
| 101 | + int ans = 0; |
| 102 | + sort(ages.begin(), ages.end()); |
| 103 | + int y_l = 0; |
| 104 | + while (y_l < ages.size() && ages[y_l] <= 14) { |
| 105 | + y_l++; |
| 106 | + } |
| 107 | + for (int y_r = y_l, x = y_l; x < ages.size(); x++) { |
| 108 | + while (ages[y_l] * 2 <= ages[x] + 14) { |
| 109 | + y_l++; |
| 110 | + } |
| 111 | + while (y_r + 1 < ages.size() && ages[y_r + 1] <= ages[x]) { |
| 112 | + y_r++; |
| 113 | + } |
| 114 | + ans += y_r - y_l; |
| 115 | + } |
| 116 | + return ans; |
| 117 | + } |
| 118 | +}; |
| 119 | +``` |
| 120 | +
|
| 121 | +## 方法二:桶排序 |
| 122 | +
|
| 123 | +有没有一种办法避免方法一的时间瓶颈——排序呢?当然有。 |
| 124 | +
|
| 125 | +不难发现每个人的年龄范围是`1`到`120`,因此我们只需要统计一下每个年龄段分别有多少人,再枚举`x`和`y`的年龄判定是否符合第一第二两个条件就好了。 |
| 126 | +
|
| 127 | ++ 时间复杂度$O(n + C^2)$:其中$C=120$ |
| 128 | ++ 空间复杂度$O(C)$ |
| 129 | +
|
| 130 | +### AC代码 |
| 131 | +
|
| 132 | +#### C++ |
| 133 | +
|
| 134 | +```cpp |
| 135 | +/* |
| 136 | + * @Author: LetMeFly |
| 137 | + * @Date: 2021-12-27 09:00:07 |
| 138 | + * @LastEditors: LetMeFly |
| 139 | + * @LastEditTime: 2021-12-27 09:07:32 |
| 140 | + */ |
| 141 | +int a[121]; |
| 142 | +class Solution { |
| 143 | +public: |
| 144 | + // age[y] * 2 <= age[x] + 14 |
| 145 | + int numFriendRequests(vector<int>& ages) { |
| 146 | + for (int i = 0; i < 121; i++) |
| 147 | + a[i] = 0; |
| 148 | + for (int& t : ages) |
| 149 | + a[t]++; |
| 150 | + int ans = 0; |
| 151 | + for (int y = 1; y <= 120; y++) { |
| 152 | + for (int x = y; x <= 120; x++) { |
| 153 | + if (y * 2 <= x + 14 || (y > 100 && x < 100)) |
| 154 | + continue; |
| 155 | + ans += x == y ? a[x] * (a[x] - 1) : a[x] * a[y]; |
| 156 | + } |
| 157 | + } |
| 158 | + return ans; |
| 159 | + } |
| 160 | +}; |
| 161 | +``` |
| 162 | + |
| 163 | +> 同步发文于CSDN和我的[个人博客](https://blog.letmefly.xyz/),原创不易,转载经作者同意后请附上[原文链接](https://blog.letmefly.xyz/2024/11/17/LeetCode%200825.%E9%80%82%E9%BE%84%E7%9A%84%E6%9C%8B%E5%8F%8B/)哦~ |
| 164 | +> |
| 165 | +> Tisfy:[https://letmefly.blog.csdn.net/article/details/143836115](https://letmefly.blog.csdn.net/article/details/143836115) |
0 commit comments