一、题目描述
绘制直线。有个单色屏幕存储在一个一维数组中,使得32个连续像素可以存放在一个 int 里。屏幕宽度为w,且w可被32整除(即一个 int 不会分布在两行上),屏幕高度可由数组长度及屏幕宽度推算得出。请实现一个函数,绘制从点(x1, y)到点(x2, y)的水平线。
给出数组的长度 length,宽度 w(以比特为单位)、直线开始位置 x1(比特为单位)、直线结束位置 x2(比特为单位)、直线所在行数 y。返回绘制过后的数组。
示例1:
输入:length = 1, w = 32, x1 = 30, x2 = 31, y = 0
输出:[3]
说明:在第0行的第30位到第31为画一条直线,屏幕表示为[0b000000000000000000000000000000011]
示例2:
输入:length = 3, w = 96, x1 = 0, x2 = 95, y = 0
输出:[-1, -1, -1]
二、解题思路
核心思想:定位到开始和结束的int,将这两个和其中间的所有int全部置为-1,然后再把线段两侧位置(两个int)通过位移运算置为0。
由题意得我们需要构建一个vector数组,int数组内形成一长串比特位,既: /0(共32个0)0/0(共32个0)0/0(共32个0)0/...... 共w/32个int,此为一行。 /0(共32个0)0/0(共32个0)0/0(共32个0)0/...... 共w/32个int,此为一行。 /0(共32个0)0/0(共32个0)0/0(共32个0)0/...... 共w/32个int,此为一行。 /...... /......共 length/每行int数 行。
通过题目后会变成:在某一行上, /...... /n(n大于等与0)个0, 至少2个1 ,n(n大于等与0)个0/ /...... 我们先大体定位到直线两个点所经过的int,将这些int全部置为0xffffffff,即-1; 让后我们通过x1,x2精准定位开始点所在的int左边需要空出几个0,结束点所在的int右边需要空出几个0。 然后通过位移运算把需要的0给空出来。
当x1与x2在同一个int上时,需要在右移时多移动 右边需要空出几个0 的位置, 以便把右边的1挤掉,然后通过左移再移回去,借以实现空出右边0的目的。
位移时应注意对有符号的整数进行右位移时,会以这个整数的符号补最左边的位置, 详情请google逻辑位移与算数位移。
二、方法步骤:
兄弟们看到这有思路了吗?哈哈,我猜题目还没先看懂,本菜鸡也是看了好久的题目,不过这是习以为常的事啦!那么实现来给大家大概讲解一下,题目的意思。
- 创建一个总共有length*32像素的数组并置位为0后合并为字符串
- 拼接字符串,将x1~x2替换为1(其实题目到这里就该结束了,没想到之后才是噩梦)
- 题目要求返回一个int类型的数组,所以先按照每32位一组进行分割
- 拿到32位字符串后有两种情况要考虑:正数与负数
- 正数情况:直接parseInt完事
- 负数情况:特征为高位为1,先转换为2进制减1再取反(注意取反符号~直接帮我们转换为十进制int了),最后乘上-1
- 将其按顺序压入数组,返回,结束 代码
三、代码
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 result = [];
for (let i = 0; i < length * 32; i += 32) {
let temp = str.substring(i, i + 32);
if (temp[0] === "1") {
temp = ~(parseInt(temp, 2) - 1);
temp *= -1;
}else {
temp = parseInt(temp, 2);
}
result.push(temp);
}
return result;
};
四、总结
题目要看懂需要一些时间和耐心,把问题梳理清晰,找到解决的方法,一步一步实现,一开始确实难以理解,不过通过上网查看,查找帖子,方法,一步一步学习过来的,慢慢理解,慢慢转化为自己的知识,还是花了很多时间的。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 juejin.cn/post/693314…