📜  门| Sudo GATE 2021 测验 |第 36 题(1)

📅  最后修改于: 2023-12-03 15:28:47.298000             🧑  作者: Mango

Sudo GATE 2021测验 - 第 36 题

本题是关于"门"的编程题,需要将一个长度为n的01序列转换为另一个长度为n的01序列,每个位置上的0和1都有可能被变换。具体来说,对于长度为n的01序列s,如果s中包含l个连续的1,那么s中所有长度不大于l的前缀都要被翻转(即0变1,1变0)。

以下是一个例子:

输入: s = "0011101",输出: "1101010"。

原因:

  • 从左到右看,"00" 没有1,无需翻转;
  • "0011" 中包含两个连续的 "1",翻转前缀 "0011",得到 "1101";
  • "01" 中包含一个连续的 "1",翻转前缀 "01",得到 "10";
  • "1" 是一个 "1",无需翻转;
  • "0" 是一个 "0",无需翻转。

终结果是 "1101010"。

解题思路

可以观察到,只有 l+1, l+2, ..., n 位置上的 0 会被翻转,因此我们不妨将这些位置都记录下来,然后一次性地对它们进行翻转,可以做到 O(n) 的时间复杂度。

如何快速找到每个位置上的最长连续 1 的长度呢?可以利用区间遍历的思想,从左向右扫描一遍数组,记录一个变量 l 表示上一个 0 的位置,每次遇到 0 时,将当前位置减去 l 得到的就是上一个 1 的连续区间的长度。这样可以做到 O(n) 的时间复杂度。

代码实现

下面是 Python 3 的代码实现。注意代码中的 n 表示输入序列的长度,变量 s 表示输入的字符串。

def flip(s):
    # Step 1: Compute the length of each 1 sequence
    last_zero_idx = -1
    lengths = []
    for i in range(n):
        if s[i] == '0':
            lengths.append(i - last_zero_idx - 1)
            last_zero_idx = i
    lengths.append(n - last_zero_idx - 1)

    # Step 2: Flip 0's at positions l+1, l+2, ..., n
    idx = 0
    for l in lengths:
        if l > 0:
            start = idx + l    # exclusive
            end = min(start + l, n)
            for i in range(start, end):
                s[i] = '1' if s[i] == '0' else '0'
        idx += l + 1

    return s

时间复杂度为 O(n)。