事情是这样的:认识了一年多的女生,最近发现她居然有10多万的网贷债务,还跟他说这些债务是“彩礼的一部分”。
这位程序员小哥直接给了她一刀,表示“不会娶一个快30岁负债累累的女生,自己去找父母还债吧。” 本以为她会立刻离开,结果她居然赖在他的房子里不走,天天等着他下班,给他添堵。
我能理解他的心情。谁受得了?你拼命加班工作,挣来的钱本该用来改善自己的生活,结果却被一个不靠谱的女人给“浪费”了。
你问我怎么让这种人主动滚蛋?首先,勇敢地设立界限!如果她真有“彩礼”这种奇葩的借口,那她自己去找家里人解决,不是你的责任。
其次,不要觉得自己对她有责任,拒绝不等于不关心,但不能让自己在这种关系中耗尽了时间和精力。
最重要的是,要清楚地认识到,自己的时间和金钱都是有限的,不能随便拿来“修复”别人给你带来的麻烦。
要有底线,不然真的是自己给自己找麻烦。搞定自己的生活,远离这些拖累,才是聪明人的做法。
算法题:有效三角形的个数
嗨,大家好。今天咱们聊聊一道挺经典的算法题——“有效三角形的个数”。说实话,这道题给我第一眼看的时候,我脑袋里立刻浮现出的是数学课上三角形的定义:三条边满足三角形不等式定理。也就是说,任意两条边之和必须大于第三条边。那么,这道题的本质就是要判断给定的边长能否组成一个有效的三角形,而这个判断条件就成了我们解决问题的关键。
题目大概是这样的:给定一个长度为n的整数数组,表示三条边的长度,你需要计算可以从数组中选取三条边,且它们能组成一个有效三角形的三元组个数。
听起来是不是很简单?选三条边,检查一下它们是否满足三角形不等式。其实,这个问题表面简单,实际考验的正是如何高效地计算出这些三元组,避免暴力解法的时间复杂度过高。
看看暴力解法
首先,我们来想象一下暴力解法。暴力解法的思路就是三重循环,遍历所有的三条边组合,检查它们是否满足三角形不等式定理:
public class TriangleCount {
public int countTriangles(int[] nums) {
int n = nums.length;
int count = 0;
for (int i = 0; i < n - 2; i++) {
for (int j = i + 1; j < n - 1; j++) {
for (int k = j + 1; k < n; k++) {
if (nums[i] + nums[j] > nums[k] &&
nums[i] + nums[k] > nums[j] &&
nums[j] + nums[k] > nums[i]) {
count++;
}
}
}
}
return count;
}
}
这段代码确实能解决问题,但它的时间复杂度是O(n³),显然对于较大的输入数据,性能会非常低下。对于数组长度达到1000的情况,简直是想让程序员崩溃。所以我们得想办法优化一下。
优化思路:排序 + 双指针
通过排序和双指针方法,我们可以将时间复杂度优化到O(n²),具体是怎么做的呢?我们来详细分析一下。
首先,排序能帮助我们大大减少不必要的比较。因为当数组排好序之后,任意三条边满足
nums[i] + nums[j] > nums[k]
,就自动满足nums[i] + nums[k] > nums[j]
和nums[j] + nums[k] > nums[i]
。只要nums[i] + nums[j] > nums[k]
成立,其他两个条件就自动成立了。然后,我们可以固定一个边,使用双指针去判断剩下的两边。比如,我们固定
nums[k]
作为最大边,然后使用两个指针i
和j
,分别指向nums[k-1]
之前的部分,来查找满足条件的组合。
代码实现如下:
import java.util.Arrays;
public class TriangleCount {
public int countTriangles(int[] nums) {
Arrays.sort(nums); // 先排序
int count = 0;
int n = nums.length;
for (int k = 2; k < n; k++) { // 固定最大边 nums[k]
int i = 0, j = k - 1; // 双指针,i指向最小边,j指向倒数第二个边
while (i < j) {
if (nums[i] + nums[j] > nums[k]) {
count += (j - i); // 说明从i到j之间所有组合都满足条件
j--;
} else {
i++;
}
}
}
return count;
}
}
解析
我们先对数组进行排序,这一步的时间复杂度是O(n log n)。 然后,我们通过一个循环固定最大的边 nums[k]
,接下来,使用两个指针i
和j
分别从0
和k-1
开始,来寻找满足三角形不等式的组合。这个过程的时间复杂度是O(n²)。当 nums[i] + nums[j] > nums[k]
时,意味着从i
到j
之间所有的组合都符合要求,因此我们可以直接加上(j - i)
个三元组。然后,移动指针j
,继续寻找其他可能的组合。如果不满足条件,则移动指针i
,尝试增加nums[i]
的值。
最终,整体时间复杂度就是O(n²),比暴力解法高效得多。
小结
通过这种排序 + 双指针的方法,我们将问题的时间复杂度从O(n³)优化到了O(n²),大大提高了程序的性能。对于大规模的数据,性能的提升是非常明显的。
而且,这道题也让我想到了一个很有趣的点,解决算法问题时,很多时候你不只是想着如何暴力解题,而是通过观察数据的结构,找到一种更加巧妙的方式来减少计算量,就像这道题中通过排序和双指针的方式,我们实际上是利用了数据的顺序性来降低了时间复杂度。
-END-
以上,就是今天的分享了,看完文章记得右下角给何老师点赞,也欢迎在评论区写下你的留言。