Python技术迷

破防!十面字节仍被挂,新称号“挂面”,一直面,一直挂 …

刚看到个贴子,说有同学秋招在字节连续面了十次、换了四个岗位,结果还是被挂,网友还给他整了个外号叫“挂面”,一句“一直面,一直挂”,确实有点扎心。

Image

网友的玩梗虽然好笑,但对当事人来说估计真挺破防的。

十次面试听着夸张,其实不少人都经历过类似的“仰卧起坐式”进度条。

我的看法是,这位同学能坚持到第十次,已经比绝大多数人强得多了。有网友说“十次还不懂放弃”,但我反而挺佩服这种韧劲。

不过话说回来,也别把希望押在某一家上,多条赛道一起走,成功率才高点。

心态别崩,路不会只剩这一条,招也不会只剩这一季。撑住,就是胜利。【备注:文末可领最新资料】

面试题:凸多边形

我跟你说啊,昨天晚上快十一点了,我还在公司楼下奶茶店那儿改一个前端小 demo,本来想画个「多边形选区」玩玩,结果一运行,发现我画的那个多边形,有时候一拐弯就凹进去了,整块区域看着特别别扭。那个时候我脑子里第一个冒出来的词就是:哎,这玩意儿到底是不是“凸多边形”啊?

所以我们就从这个特别接地气的小问题聊起:怎么用 Python 判断一个多边形是不是凸的。

先把概念说清楚,不然容易绕

你可以先想象一下拿铅笔在纸上连点的感觉: 有一堆点,按顺序连起来,最后首尾一接,就是一个多边形。

所谓「凸多边形」,其实有一个很好理解的口径: 你随便在这个多边形里画一条直线,只要这条线两头都在多边形里面,那整条线都不会跑到外面去,这种就是“凸”的。 反过来,要是多边形中间有个“坑”,像一个月牙那样,线段可能会戳到外面去,那就是“凹”的。

但是你在代码里不可能真拿无数条线去试,那怎么搞? 程序员的老办法:用向量和叉积(cross product)来判断“拐弯的方向”。

口头版思路先走一遍

想象你沿着多边形的边,一路走过去: 每次你从点 A 走到点 B,再走到点 C,这个时候你在 B 这个点其实做了一次“转弯”。

如果这个多边形是凸的,而且所有顶点是按同一个方向排的(比如统一按逆时针),那你一路走下来,要么每次都是左转,要么每次都是右转,反正“转向”是统一的。 一旦中间有一次转成了另外一个方向,那就说明这里凹进去了,多半不是凸的。

数学上怎么表达“左转 / 右转”? 就是用叉积的符号:

  • 三个点 A(x1,y1), B(x2,y2), C(x3,y3)
  • 向量 AB = B - A
  • 向量 BC = C - B

叉积的 z 分量:

cross = (B - A) x (C - B)
      = (x2 - x1, y2 - y1) 和 (x3 - x2, y3 - y2) 的叉积
      = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2)
  • cross > 0,可以理解成一个方向(比如“左转”)
  • cross < 0,就是反方向(比如“右转”)
  • cross = 0,三点共线,等于没拐弯

我们的目标就是: 把多边形所有连续三点的 cross 都算一遍,只要出现了正的,又出现了负的,那就不是凸多边形。

用 Python 把这个想法写出来

先来一个判断函数,输入是一串点,点按顺时针或逆时针顺序排好,比如:[(x1, y1), (x2, y2), ..., (xn, yn)]

from typing import List, Tuple

Point = Tuple[float, float]

defis_convex_polygon(points: List[Point]) -> bool:
"""
    判断一个多边形是否为凸多边形
    points: 按顺时针或逆时针顺序给出的顶点列表
    返回 True 表示是凸多边形,False 表示不是
    """

    n = len(points)
# 顶点少于3个,严格意义上都谈不上多边形,这里直接当成 True 或 False 都行
if n < 3:
returnFalse

defcross(o: Point, a: Point, b: Point) -> float:
# 计算 OA × OB 的叉积,这里 O 是中间点
return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])

    sign = 0# 用来记录第一次非 0 叉积的符号
for i in range(n):
        o = points[i]
        a = points[(i + 1) % n]
        b = points[(i + 2) % n]
        c = cross(o, a, b)
if c == 0:
# 三点共线,既不算左转也不算右转,直接跳过
continue
if sign == 0:
            sign = 1if c > 0else-1
else:
# 一旦发现当前叉积的符号和之前不一样,就不是凸的
if (c > 0and sign < 0) or (c < 0and sign > 0):
returnFalse

# 如果一路下来看,没有出现符号冲突,就是凸多边形
returnTrue

上面这个代码就是翻译我们刚刚那段“绕多边形走一圈看转向”的思路。 注意我在循环里用了 (i + 1) % n 这种写法,是为了首尾相接,最后那几条边也能算进去,不会漏掉。

顺便再加点“实用功能”:算面积

一般面试或者刷题,凸多边形这块除了“判断是不是凸的”,还经常会让你算面积,尤其是前端画布、游戏场景那种,面积用得挺多。

凸不凸跟面积算法其实没关系,普通简单多边形(不自交)都能用「鞋带公式」算面积,代码也挺短。

defpolygon_area(points: List[Point]) -> float:
"""
    用鞋带公式计算多边形面积
    顶点顺时针或逆时针给出都可以
    """

    n = len(points)
if n < 3:
return0.0
    s = 0.0
for i in range(n):
        x1, y1 = points[i]
        x2, y2 = points[(i + 1) % n]
        s += x1 * y2 - x2 * y1
return abs(s) / 2.0

你可以先用 is_convex_polygon 过滤一下,只对凸的多边形做下一步计算,当然如果题目明确说“输入保证是凸多边形”,那就不用多此一举了。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB