LeetCode 算法:绘制直线

104 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 16 天,点击查看活动详情

绘制直线

原题地址

已知一个由像素点组成的单色屏幕,每行均有 w 个像素点,所有像素点初始为 0,左上角位置为 (0,0)

现将每行的像素点按照 「每 32 个像素点」 为一组存放在一个 int 中,再依次存入长度为 length 的一维数组中。

我们将在屏幕上绘制一条从点 (x1,y) 到点 (x2,y) 的直线(即像素点修改为 1),请返回绘制过后的数组。

 

注意:

  • 用例保证屏幕宽度 w 可被 32 整除(即一个 int 不会分布在两行上)  

示例1:

 输入:length = 1, w = 32, x1 = 30, x2 = 31, y = 0
 输出:[3]
 解释:在第 0 行的第 30 位到第 31 位画一条直线,屏幕二进制形式表示为 [00000000000000000000000000000011],因此返回 [3]

示例2:

 输入:length = 3, w = 96, x1 = 0, x2 = 95, y = 0
 输出:[-1, -1, -1]
 解释:由于二进制 11111111111111111111111111111111 的 int 类型代表 -1,因此返回 [-1,-1,-1]

提示:

  • 1 <= length <=10510^5
  • 1 <= w <= 3 *10510^5
  • 0 <= x1 <= x2 < w
  • 0 <= y <= 10

思路分析

  1. 首先分析题目,翻译成通俗易懂的文字来解释,一行有 w 个像素点,即有 w / 32int,然后从 (x1,y)(x2,y) 位置上的为 1,其余位置均为 0,然后以 32 个像素为一个单位计算其整数值,然后存储在长度为 length 的数组中,整体画布大小长为 w,高为 length / (w / 32)
  2. 理解题目后,我们来解题,思路是将画布整体转换为字符串来解决;
  3. 第一步:先构建一个 length * 32 且每个字符均为 0 的字符串;
  4. 第二步:画线,将 (x1,y)(x2,y) 的位置替换成 1,替换的长度为 x2 - x1 + 1,替换的起始点为 y * w + x1,终止点为 y * w + x2 + 1
  5. 第三步:将字符串每 32 位为一组,然后计算每组的十进制值;
  6. 第四步:遇到正数,直接将二进制转换为十进制数即可;
  7. 第五步:遇到负数,即最高位为 1,先将二进制数减1取反后乘以 -1 即为十进制数;
  8. 第六步:按照顺序转换完成后,将对应的结果存入 res 中返回即可。

AC 代码

/**
 * @param {number} length
 * @param {number} w
 * @param {number} x1
 * @param {number} x2
 * @param {number} y
 * @return {number[]}
 */
var drawLine = function(length, w, x1, x2, y) {
    let str = new Array(length * 32).fill(0).join("")
    str = str.substring(0, y * w + x1) + "1".repeat(x2 - x1 + 1) + str.substring(y * w + x2 + 1)
    let res = []
    for (let i = 0; i < length; i++) {
        let temp = str.substring(i * 32, (i + 1) * 32)
        if (temp[0] === "1") {
            temp = ~(parseInt(temp, 2) - 1)
            temp *= -1
        }else {
            temp = parseInt(temp, 2)
        }
        res.push(temp)
    }
    return res
};

结果:

  • 执行结果: 通过
  • 执行用时:116 ms, 在所有 JavaScript 提交中击败了24.00%的用户
  • 内存消耗:94.1 MB, 在所有 JavaScript 提交中击败了24.00%的用户
  • 通过测试用例:30 / 30

END