最近看到一个HR自爆裁员套路的帖子,简直看呆了。你以为自己只要认真工作就能顺利度过职场风雨,结果可能有时候那些所谓的“风雨”是HR设下的陷阱,等着你自投罗网。
看到这里,我觉得有必要提醒大家:虽然这些套路现在在很多地方已经不那么容易见到了,但依然有一些企业在黑暗中摸索,尽量避免让你得到应得的权益。
对于我们普通员工来说,要保护自己,就必须懂得法律,懂得自己的权利。最好事先学习相关的劳动法,签合同的时候仔细审查,特别是那些可能涉及霸王条款的内容,不要心存侥幸。
如果真遇到不公正对待,记得保留证据,录音、拍照都可以,毕竟,哪怕是面对HR这种“老司机”,我们也能做到以退为进,保护自己的利益。
今日算法题
好了,套路看完了,我们言归正传,今天我们来聊聊一道经典的算法题:直线上最多的点数。这道题看似简单,但背后却隐藏着一些非常有趣的思考方式。好了,不卖关子了,我们直接开始!
首先,题目给了我们一堆二维坐标点,要求我们找出一条直线,使得这条直线上的点数最多。想想看,这是不是个典型的几何问题呢?对的,就是要从这些点中,找到一条"最佳"直线,经过最多的点。
但你也许会问,既然是"直线",那难道就简单了?直线的斜率不就是一个固定的数值吗?要是只这么想,可能你会陷入一个误区。
因为不同的点和不同的坐标组合,可能会有不同的斜率,有些可能是浮动的,有些可能是特殊情况,甚至是重合的点,所以光靠简单的斜率计算是行不通的。
要解决这个问题,我们得用点的坐标计算直线的斜率。具体来说,如果你给我两个点(x1, y1)
和(x2, y2)
,那么这条直线的斜率可以用公式 (y2 - y1) / (x2 - x1)
来计算。
可惜的是,直接计算浮动的斜率会导致很多麻烦,因为浮点数的精度问题。所以我们通常会选择使用整数表示斜率,通过交叉相乘来避免除法运算,确保结果的准确性。
接下来,咱们来看看如何用 JavaScript 来实现这个想法。
我们首先需要一个循环来遍历所有的点,计算每一对点之间的斜率。然后,我们用一个哈希表来存储每个斜率出现的次数。如果两点的斜率相同,说明它们在同一条直线上,我们就增加相应的计数。最后,我们可以找出出现最多次数的斜率,也就是经过最多点的直线。
看起来很简单对吧?但在实现过程中,我们还需要考虑几个边界情况,比如重复的点或者垂直的直线(斜率无穷大)。这些情况可能导致一些特殊处理,但我们依然能通过一些小技巧把它们搞定。
下面是完整的 JavaScript 代码实现:
var maxPoints = function(points) {
if (points.length <= 2) return points.length;
let max = 0;
for (let i = 0; i < points.length; i++) {
let slopes = {}; // 用来存储每个斜率出现的次数
let duplicate = 0; // 记录重复点的个数
let vertical = 0; // 记录垂直直线的个数
let localMax = 0; // 记录当前基准点能通过的最多点数
for (let j = i + 1; j < points.length; j++) {
if (points[i][0] === points[j][0] && points[i][1] === points[j][1]) {
duplicate++; // 如果是同一个点,重复点数量加一
} else if (points[i][0] === points[j][0]) {
vertical++; // 如果是垂直线,斜率无穷大
} else {
let dy = points[j][1] - points[i][1];
let dx = points[j][0] - points[i][0];
let gcd = getGCD(dy, dx); // 计算斜率的最大公约数,避免精度问题
dy /= gcd;
dx /= gcd;
if (dx < 0) { // 保证斜率是唯一表示的
dy = -dy;
dx = -dx;
}
let slope = `${dy},${dx}`;
slopes[slope] = (slopes[slope] || 0) + 1;
localMax = Math.max(localMax, slopes[slope]);
}
}
max = Math.max(max, localMax + duplicate + 1, vertical + duplicate + 1);
}
return max;
};
function getGCD(a, b) {
while (b !== 0) {
let temp = b;
b = a % b;
a = temp;
}
return a;
}
在这个代码中,我们首先遍历每一个点,然后与其它点计算斜率。对于每一对点,如果它们的斜率相同,我们就把这个斜率的计数加一。
最后,我们从所有斜率中找出出现次数最多的那个。值得注意的是,代码中的 getGCD 函数用于求最大公约数,这样我们就能避免浮动的浮点数计算,并确保每条斜率都能够标准化。
说到这里,我们处理了重复点和垂直线这两种特殊情况。重复点我们直接加到计数器中,而垂直线则通过特殊的判断处理。最终,我们返回通过最多点的直线的点数。
这道题的关键在于如何高效地计算斜率,并且通过哈希表来存储斜率出现的次数。通过这样的处理,我们可以快速找到最多点的直线。而最大公约数的使用是解决斜率计算中的精度问题的一个非常巧妙的方法。
从时间复杂度的角度来看,外层循环遍历每个点是 O(n),而内层循环则遍历剩下的点,时间复杂度是 O(n)。因此,总的时间复杂度是 O(n^2),其中 n 是点的数量。虽然时间复杂度较高,但这已经是处理这类问题时的一个相对高效的做法了。
目前,对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
虎哥私藏精品 热门推荐 虎哥作为一名老码农,整理了全网最全《前端资料合集》。