女生和32岁大厂程序员交往半年多,最近纠结要不要分手,原因直接给我看懵了:“他不行”…
刚看到个贴子:一女生跟32岁大厂程序员谈了半年,最近纠结要不要分手,理由竟然是“他性生活不行”,确实把我看愣了。
我觉得这事吧,网友们的回帖两极分化,一边说女生现实,一边说男人问题不能忽略。
但在我看来,亲密关系本来就是情侣之间很重要的一部分,不是说要多完美,而是两个人能不能沟通、磨合、一起解决问题。
不少网友在那嘲讽女生“太挑”,我倒觉得有点武断了。三观、沟通、亲密度,这些都是长期关系的底层逻辑,忽视谁都不太行。
当然,女生如果只是想以这个理由“一票否决”,那也得想清楚:半年都不愿意尝试沟通,那以后很多事情可能也会卡壳。
换个角度说,男生也别觉得这是羞耻话题,亲密问题就像电脑系统卡顿,能调能修,关键是敢不敢面对。【备注:文末可领最新资料】
面试题:凸多边形
先把场景脑补一下哈:周五晚上,测完接口正准备下班,产品突然甩过来一句——“给你一堆点,你看看这是不是凸多边形,顺便用 Java 写个算法,后面还要用”。所以这篇就当是你写完代码、顺手记下来的随手笔记,别太学术那种。
啥是凸多边形?
特别简单,你就记一个标准:
对于一个多边形里的任意两点,连一条线,这条线要“完全待在”多边形里面,那它就是凸的。
反过来,如果你画一条线会戳出多边形外面一截,那就是凹的。 再直白一点:凸多边形的外形不会有“内凹进去的小坑”。
编程上我们一般有一串点 P0, P1, P2, ..., Pn-1,按顺时针或逆时针连起来,就是一个多边形。问题就是:这串点对应的这玩意儿,到底凸不凸?
看拐弯方向是不是一直一样
几何里有个很好用的小工具:叉积(cross product)。 你不用推导公式,直接记结论就行:
对三个点 A、B、C,看向量 AB 和 BC 的叉积:
叉积 > 0:一个方向拐(比如统一逆时针) 叉积 < 0:反方向拐(顺时针) 叉积 = 0:三点共线,不拐
如果一个简单多边形是凸的,那你沿着边走一圈,所有“拐弯方向”要么全是左转,要么全是右转,不能中途“反悔”一下。
所以算法就变成:
遍历每个点 i,取三点: prev = i-1、curr = i、next = i+1(注意用取模,首尾要连起来)。计算 cross((curr - prev), (next - curr))。记录第一个非 0 的叉积符号,后面每次出现非 0 的,符号必须跟它一样,否则就不是凸多边形。
时间复杂度 O(n),一圈扫完就行。
直接上代码,写得口语一点,方便你改:
publicclassConvexPolygonChecker{
// 简单的点结构
staticclassPoint{
long x;
long y;
Point(long x, long y) {
this.x = x;
this.y = y;
}
}
// 计算叉积: (b - a) × (c - b)
privatestaticlongcross(Point a, Point b, Point c){
long abx = b.x - a.x;
long aby = b.y - a.y;
long bcx = c.x - b.x;
long bcy = c.y - b.y;
return abx * bcy - aby * bcx;
}
// 判断一串点是否构成凸多边形(假设点按顺/逆时针给好,且不自交)
publicstaticbooleanisConvex(List<Point> points){
int n = points.size();
if (n < 3) returnfalse; // 三个点以下没法叫多边形
int sign = 0; // 记录第一次非 0 的叉积符号
for (int i = 0; i < n; i++) {
Point a = points.get((i - 1 + n) % n);
Point b = points.get(i);
Point c = points.get((i + 1) % n);
long crossVal = cross(a, b, c);
if (crossVal == 0) {
// 共线就先忽略,看后面
continue;
}
int currSign = crossVal > 0 ? 1 : -1;
if (sign == 0) {
sign = currSign; // 第一次发现拐弯方向
} elseif (sign != currSign) {
// 出现反方向拐弯,必然不是凸多边形
returnfalse;
}
}
// 如果全是共线(degenerate)那算不算凸你可以按题意决定
return sign != 0;
}
}
几个小点随手说一下:
坐标我用 long,防止大数据乘法爆int。如果所有点共线( sign一直是 0),理论上这是个“退化多边形”,有的题会说不是多边形,有的会当成特殊凸多边形,根据题目要求改 return。前提是点已经按顺时针或逆时针排好了;如果是乱序点,那是凸包问题,得先做一遍凸包再说。
点在凸多边形内判断
既然都聊到凸多边形了,面试常见搭配还有一句:“再顺便写下点在凸多边形内的判断呗”。
凸多边形就有个好处:判断是不是在里面,可以用“方向一致”这套逻辑再用一次。 思路很像刚才:
固定一个点 P; 对每条边 (Vi, V(i+1)),算叉积 cross(Vi, V(i+1), P);如果所有叉积都同号(允许等于 0,说明在边上),就认为在多边形内。
简化版代码大概这样:
publicstaticbooleanpointInConvexPolygon(List<Point> poly, Point p){
int n = poly.size();
int sign = 0;
for (int i = 0; i < n; i++) {
Point a = poly.get(i);
Point b = poly.get((i + 1) % n);
long crossVal = cross(a, b, p);
if (crossVal == 0) continue;
int currSign = crossVal > 0 ? 1 : -1;
if (sign == 0) {
sign = currSign;
} elseif (sign != currSign) {
returnfalse;
}
}
returntrue; // 在内部或边上
}
很多 OJ 会把这两个题一起考:先判断是不是凸多边形,再判断一堆点是不是在里面,代码直接复用叉积就行。
乱序点怎么变成凸多边形(凸包)
现实里更多是这样一个需求:给你一堆散点,先把“外壳”找出来——这层外壳其实就是一个凸多边形,这个操作就叫求凸包。
常见做法有 Graham Scan、Andrew 算法,核心都是:
先把点按 x、y 排个序; 从左到右构建下凸壳,每加一个点就看“是不是反方向拐弯”,如果是就把中间那个点弹掉; 再从右到左构建上凸壳; 拼在一起就是一圈凸多边形点。
你会发现,还是那句老话:全靠叉积看拐弯方向,套路非常统一。
Java 写一遍也不难,就是排序 + 一个栈维护,篇幅就不展开写全代码了,你要是后面真要用,我可以帮你把凸包那段也补全成工具类,直接丢项目里用。
大概就这样,凸多边形相关的几个常用算法: 判断是不是凸、点是否在凸多边形内、以及顺嘴提了一下如何从一堆点“长出”一个凸多边形。 剩下就是老三件套:多测几组数据、注意顺逆时针、注意 long 溢出,就差不多可以愉快交差了。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html