用线性代数解前端面试题

733 阅读2分钟

前几天看到一个面试题,如下图:

640.png

大概意思就是任意给一个鼠标位置,求鼠标位置是在哪个区域,上三角?下三角?还是正好在分割线上?

原文链接

解法很简单原文里有介绍: 用x/y和宽/高比较下就能得到结果。

原文中也提到了可以用线性代数来解这道题,正好最近在研究线性代数,下面介绍下自己的解题思路:

第一步: 画一个坐标轴,随意取了一个向量(红线)。这里用了[1,1]; image.png

// 省略了部分代码,可去github上查看全部代码(文末有链接)
const axis = new Axis(world, {
  x: [-5, 6],
  y: [-5, 6],
});

const target = [1, 1];

// 渲染标准空间坐标系,(设为A空间)
axis.render();
axis.renderV(target);

第二步: 利用空间变换将坐标轴逆时针旋转(为了更方便做对比,我保留了原坐标系图),变换后的正方向X轴可以看做是题目中的上下三角的分割线。

image.png

axis.setBasis([
  [Math.cos((Math.PI / 180) * 30), Math.sin((Math.PI / 180) * 30) * -1, 0],
  [Math.sin((Math.PI / 180) * 30), Math.cos((Math.PI / 180) * 30), 0],
  [0, 0, 1],
]);
// 渲染变换后坐标系,(设为B空间)
axis.render();
axis.renderV(target);

第三部: 把变换前的[1,1]向量(图中黄色向量)用变换后的坐标系的向量来表示,即可得到解。

image.png

// B空间的基取逆后,点乘A空间的向量就是: 用B空间的向量表示A空间的此向量
const tmp = transform(
  inv([
    [Math.cos((Math.PI / 180) * 30), Math.sin((Math.PI / 180) * 30) * -1, 0],
    [Math.sin((Math.PI / 180) * 30), Math.cos((Math.PI / 180) * 30), 0],
    [0, 0, 1],
  ]),
  target
);

axis.renderV(tmp, 'yellow');

console.log(tmp); // [1.3660254037844386, 0.36602540378443876]

原坐标系向量[1,1],用变换后的坐标系来表示为[1.3660254037844386, 0.36602540378443876], y值为大于0的值,所以[1,1]在上三角区域里。

完整代码:github.com/conanjunn/l…