额……首先,这道题我是做出来了,只是解法过于简单粗暴,所以参考价值不大。
本着一半是为了将来的我能够看到进步的原则,还是记录一下吧。
1、先看题
题目不短也不长,一边说了题意也一边铺了烟雾弹。
往下看吧。
2、审题
这道题有很多地方讲解地不明不白的,虽然你可能能够知道要做些什么,但却有些细节让你不好动手。
且听我慢慢分解吧。
- 题目给出了3个条件,但实际上只有2个。稍微动下脑子就会发现,条件3已结被条件2涵盖进去了。
- 每个条件都是从x向y发送请求的角度出发的。而满足任一条件,则不会发出请求
如果 x 向 y 发送一条好友请求,y 不必也向 x 发送一条好友请求
。这句话就是一烟雾弹,实际的理解是如果满足条件,则x可以向y发请求。然后换过来考虑,如果y也符合向x发请求的条件,那么它也可以发出请求。- case1指出,如果两个人的年龄相同,则可以互相发送请求,算作2条。等于是上面一条要点的应用。
我在厘清了条件后,就开始动手了,毕竟题目就已经给清了条件语句,所以实现起来似乎没什么困难的。
直到我遇上了一堆超时,修修改改提交成功,看到耗时排名后我才知道—— too native!
3、思路
我花了写时间在厘清题目给出的条件上。
首先我们可以发现,在条件2的基础上,条件3就是废话。条件2规定了x的年龄必须大于等于y。
在此基础上,我想到了首先对整个队列进行排序,这样就可以保证单向的比较上,年龄大于等于的要求可以忽略掉。
其次是条件1,当你以x的角度出发去比较时,由于x的年龄是固定的,所以0.5 * age[x] + 7
将始终是固定值,则我们可以根据此为标准,快速的得出哪些人可以发出请求。
同时,由于队列已经是递增的了,我们也能知道何时跳出比较。
想到这,整体思路就成形了。
4、开工!
class Solution {
public int numFriendRequests(int[] ages) {
int ans = 0;
Arrays.sort(ages);
for (int i = ages.length - 1; i >= 1; i--) {
int ageLine = (int) (0.5 * ages[i] + 7);
for (int j = i - 1; j >= 0; j--) {
//年龄不够后,跳出循环
if (ages[j] <= ageLine) {
break;
}
ans++;
//年龄一致时可以互粉
if (ages[i] == ages[j]) {
ans++;
}
}
}
return ans;
}
}
看着很简洁是吧。
但这解法除了好想好写外就是个jb……
5、解读
跳过,没脸讲解什么,下面会放出大牛们的精彩解法,大家学那些吧。
你可得给劲了,将来的我……
6、提交
毕竟是接近O(n2) 的实现,就这样吧……
7、大牛们来了
快进到开脑洞
这里依旧是有请三叶大佬吧。
人不仅解法出色,解释清楚,还画出了漂亮的图。
知道差距了吧
大佬提供了两种解法,双指针 和 前缀和。
双指针想法与我的类似,但在计算单个人的可交友数量时更加快捷,单个用户的耗时为O(logN),于是可以让整体的时间复杂度来到O(NlogN)。
但你以为这就完了?
前缀和让你小刀划屁股——开开眼!整点通辽话
具体实现和思路看大佬讲解吧……
前缀和实际上是我比较擅长的解法,毕竟空间换时间的思路很符合我。实际上在发现我的解法耗时奇差时,我就想过通过前缀和的思路去优化,但始终没有绕过弯。
现在看来,我始终是在ages[] 上考虑应用前缀和,但大牛们却是在年龄上使用。从这一点就直接分出来胜负。
8、总结
虽然是中等题,但却也让我学到了很多啊。
现实中不乏牛人,但更多的可能只是像我这样的泛泛之辈……
尽管我们努力可能也永远够不大牛们的后脚跟,但如果不努力,你连努力的凡人也无法触及。
所以,加油吧社畜
与各位凡人社畜,共勉。