leetcode
leetcode 2801 ~ 2850
绘制直线

绘制直线

难度:

标签:

题目描述

A monochrome screen is stored as a single array of int, allowing 32 consecutive pixels to be stored in one int. The screen has width w, where w is divisible by 32 (that is, no byte will be split across rows). The height of the screen, of course, can be derived from the length of the array and the width. Implement a function that draws a horizontal line from (x1, y) to (x2, y).

Given the length of the array, the width of the array (in bit), start position x1 (in bit) of the line, end position x2 (in bit) of the line and the row number y of the line, return the array after drawing.

Example1:

 Input: length = 1, w = 32, x1 = 30, x2 = 31, y = 0
 Output: [3]
 Explanation: After drawing a line from (30, 0) to (31, 0), the screen becomes [0b000000000000000000000000000000011].

Example2:

 Input: length = 3, w = 96, x1 = 0, x2 = 95, y = 0
 Output: [-1, -1, -1]

代码结果

运行时间: 27 ms, 内存: 16.3 MB


/*
 * 思路:
 * 1. 与普通 Java 方法相同的逻辑,只是利用 Java Stream 来处理。
 * 2. 我们将使用 IntStream 和 lambda 表达式来处理屏幕的绘制。
 */
import java.util.stream.IntStream;

public int[] drawLine(int length, int w, int x1, int x2, int y) {
    int[] screen = new int[length];
    int startIdx = y * (w / 32) + (x1 / 32);
    int endIdx = y * (w / 32) + (x2 / 32);
    int startOffset = x1 % 32;
    int endOffset = x2 % 32;

    if (startIdx == endIdx) {
        screen[startIdx] |= ((1 << (endOffset - startOffset + 1)) - 1) << (31 - endOffset);
    } else {
        screen[startIdx] |= ((1 << (32 - startOffset)) - 1) << startOffset;
        IntStream.range(startIdx + 1, endIdx).forEach(i -> screen[i] = -1);
        screen[endIdx] |= (1 << (endOffset + 1)) - 1;
    }
    return screen;
}

解释

方法:

这个题解通过分段绘制直线来处理问题。首先计算出每行32个像素对应一个整数值,再根据输入的x1和x2计算出要修改的整数范围。题解的主要步骤包括:1. 计算影响到的起始和结束索引。2. 对于起始和结束索引内的所有整数,设置为全1(即-1,因为整数中的32个1表示的二进制数转换为整数是-1)。3. 对于起始和结束索引,根据x1和x2的位置设置相应的位。4. 如果x1和x2在同一个整数内,需要特别处理这一整数的位。5. 使用_to32bit函数处理整数的表示,确保返回的整数值是正确的(处理了整数的符号位)。

时间复杂度:

O(length)

空间复杂度:

O(length)

代码细节讲解

🦆
为什么在初始化结果数组时,使用的是长度为`length`的数组,而不是基于屏幕宽度`w`和高度来计算所需数组的大小?
这里的`length`实际上代表整个屏幕所需的整数数量,而不是像素数量。由于每个整数包含32个像素(即一个整数可以表示一行中的32个像素),因此整个屏幕的像素通过一系列整数来表示。`length`已经是按照整数计算的总量,可能由调用者根据屏幕的宽度`w`和高度计算得到,并传入函数中。这样直接使用`length`可以简化计算过程,避免在函数内部重复计算屏幕所需的整数数量。
🦆
在计算起始和结束索引时,为什么要加上`width * y`,这里的`y`是如何影响整个索引的计算的?
`width * y`是计算从屏幕顶部开始到指定行`y`为止所需跳过的整数总数。因为每一行占据`width`个整数,所以`y`行之前的所有像素占据的整数总数就是`width * y`。这样,当我们在第`y`行绘制从`x1`到`x2`的直线时,可以通过这个计算直接定位到这一行的起始和结束整数索引,从而正确设置这些整数的对应位。
🦆
函数`_to32bit`用于处理负数情况,但是这里的例子是否真的会出现整数值为负数的情况?如果会,是在什么情况下?
在这个题解中,负数的情况确实可能发生,特别是当整数全部位被设置为1时。在二进制表示中,如果一个整数的所有32位都被设置为1,它将被解释为`-1`,因为这在补码表示中代表-1。这种情况发生在我们将整数中的所有位直接设置为1(如使用`-1`或`0xffffffff`)以表示连续的32个像素被标记。因此,`_to32bit`函数确保转换后的整数值正确处理了符号位,避免错误地解释这些整数值。

相关问题