题目:
已知一个由像素点组成的单色屏幕,每行均有 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 <= 10^5
1 <= w <= 3 * 10^5
0 <= x1 <= x2 < w
0 <= y <= 10
思路:
- 首先我们应该计算是在数组的哪一个位置开始的绘制直线。开始位置索引应该为(x1 / 32) + (w / 32) * y。
- 如果开始索引和结束索引相同,即在同一个int内,那么我们应该只改变其中的部分位。
- 如果索引位置不同,那么起始块和结束块应该单独处理,中间的直接赋值-1,因为二进制 11111111111111111111111111111111 的 int 类型代表 -1。
- 起始块是从低位向高位改变,结束块是从高位向低位改变。
C代码如下:
int* drawLine(int length, int w, int x1, int x2, int y, int* returnSize) {int start_index = (x1 / 32) + (w / 32) * y; // 起始块索引int end_index = (x2 / 32) + (w / 32) * y; // 结束块索引*returnSize = length;int *ret = malloc(sizeof(int) * length); // 初始化数组memset(ret, 0, sizeof(int) * length);int start_bit = x1 % 32; // 起始位位置int end_bit = x2 % 32; // 结束位位置if (start_index == end_index) {// 同一个块中绘制int mask = ((1 << (end_bit - start_bit + 1)) - 1);ret[start_index] |= (mask << (31 - end_bit)); // 填充部分位} else {// 起始块if (start_bit > 0) {int start_mask = (1 << (32 - start_bit)) - 1;ret[start_index] |= start_mask; // 填充起始块} else {ret[start_index] = -1; // 如果起始位为0,直接填满整个块}// 中间块for (int i = start_index + 1; i < end_index; i++) {ret[i] = -1; // 填满整个块}// 结束块if (end_bit < 31) {int end_mask = (1 << (32 - end_bit - 1)) - 1;ret[end_index] |= ~end_mask; // 填充结束块} else {ret[end_index] = -1; // 如果结束位为31,直接填满整个块}}return ret;
}