题解 | #MP3光标位置#
MP3光标位置
https://www.nowcoder.com/practice/eaf5b886bd6645dd9cfb5406f3753e15
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); // 注意 hasNext 和 hasNextLine 的区别 while (in.hasNext()) { // 注意 while 处理多个 case int n = in.nextInt(); String cmd = in.next(); parseCmd(cmd, n); } } public static void parseCmd(String commands, int n) { int start = 1; int end = Math.min(n, 4); // 光标位置 int index = 1; for (int i = 0; i < commands.length(); i++) { // 根据向上移动和向下移动的公式,光标位置的变化 if (commands.charAt(i) == 'U') { index = (index - 1 - 1 + n) % n + 1; } else if (commands.charAt(i) == 'D') { index = index % n + 1; } // 判断滑动窗口的位置是否需要改变 if (index < start) { // 光标在窗口之上 start = index; end = start + 3; } else if (index > end) { // 光标在窗口之下 end = index; start = end - 3; } } // 输出窗口内容 for (int i = start; i <= end; i++) { System.out.print(i + " "); } System.out.println(); // 打印当前光标 System.out.println(index); } }
代码是赋值,说一下那个公式吧:
这行代码是在处理一个特定的滑动窗口问题,其中光标可以在一个序列上向上移动。这个问题中的滑动窗口有固定的长度,这里是4。光标的位置用 cursor
变量表示,它代表窗口的当前起始位置。
让我们分解这行代码:
cursor = (cursor - 1 - 1 + windowSize) % windowSize + 1;
- cursor - 1:这部分代码将光标向前移动一个位置。假设 cursor 的初始值是1,表示窗口的起始位置在序列的第一个元素上。那么 cursor - 1 将会把光标移动到序列的开始位置之前。
- - 1:由于我们已经将光标移动到了开始位置之前,再减1将会把光标移动到一个无效的位置(即序列的开始之前)。这个操作是为了模拟向上移动一个位置的效果。
- + windowSize:由于我们有一个固定大小的窗口,这个操作是将窗口的长度加到光标的当前位置。这样做的目的是为了在取模运算后,光标能够回到窗口的有效位置范围内。
- % windowSize:取模运算是用来确保光标的位置不会超出窗口的长度。如果光标移动后的位置加上窗口长度超出了窗口的最后一个位置,取模运算将会把光标位置调整到窗口内的一个有效位置。
- + 1:最后,我们再加上1,这是因为我们希望光标始终位于窗口的第一个位置,而不是在窗口开始之前的位置。这样,光标就正确地向上移动了一个位置,并且仍然保持在窗口的起始位置。
举个例子,如果 windowSize
是4,cursor
的初始值是1,那么执行这行代码的过程如下:
cursor - 1
将光标移动到位置0(序列开始之前)。- 再减1,光标移动到位置-1(一个无效的位置)。
+ windowSize
将光标移动到位置3(因为4 - 1 + 4 = 7,超出了窗口长度,但光标仍然在窗口内)。% windowSize
确保光标位置在0到3之间,这里是3 % 4 = 3(已经是有效位置,无需改变)。+ 1
将光标移动到位置4,这是窗口的下一个有效起始位置。
这样,光标就成功地向上移动了一个位置,同时保持在滑动窗口的范围内。