文章目录
题目
标题和出处
标题:最少的后缀翻转次数
难度
4 级
题目描述
要求
给定一个长度为 n \texttt{n} n、下标从 0 \texttt{0} 0 开始的二进制字符串 target \texttt{target} target。有另一个长度为 n \texttt{n} n 的二进制字符串 s \texttt{s} s,初始时 s \texttt{s} s 的每一位上都是 0 \texttt{0} 0。目标是让 s \texttt{s} s 和 target \texttt{target} target 相等。
一步操作中,可以选择下标 i \texttt{i} i( 0 ≤ i < n \texttt{0} \le \texttt{i} < \texttt{n} 0≤i<n)并翻转在闭区间 i, n − 1 \texttt{i, n} - \\texttt{1} i, n−1 内的所有位。翻转的含义是 '0' \texttt{`0'} '0' 变为 '1' \texttt{`1'} '1', '1' \texttt{`1'} '1' 变为 '0' \texttt{`0'} '0'。
返回使 s \texttt{s} s 与 target \texttt{target} target 相等需要的最少翻转次数。
示例
示例 1:
输入: target = "10111" \texttt{target = "10111"} target = "10111"
输出: 3 \texttt{3} 3
解释:初始时, s = "00000" \texttt{s = "00000"} s = "00000"。
选择下标 2 \texttt{2} 2: "00000" → "00111" \texttt{"00000"} \rightarrow \texttt{"00111"} "00000"→"00111"
选择下标 0 \texttt{0} 0: "00111" → "11000" \texttt{"00111"} \rightarrow \texttt{"11000"} "00111"→"11000"
选择下标 1 \texttt{1} 1: "11000" → "10111" \texttt{"11000"} \rightarrow \texttt{"10111"} "11000"→"10111"
要达成目标,需要至少 3 \texttt{3} 3 次翻转。
示例 2:
输入: target = "101" \texttt{target = "101"} target = "101"
输出: 3 \texttt{3} 3
解释:初始时, s = "000" \texttt{s = "000"} s = "000"。
选择下标 0 \texttt{0} 0: "000" → "111" \texttt{"000"} \rightarrow \texttt{"111"} "000"→"111"
选择下标 1 \texttt{1} 1: "111" → "100" \texttt{"111"} \rightarrow \texttt{"100"} "111"→"100"
选择下标 2 \texttt{2} 2: "100" → "101" \texttt{"100"} \rightarrow \texttt{"101"} "100"→"101"
要达成目标,需要至少 3 \texttt{3} 3 次翻转。
示例 3:
输入: target = "00000" \texttt{target = "00000"} target = "00000"
输出: 0 \texttt{0} 0
解释:由于 s \texttt{s} s 已经等于目标,所以不需要任何操作。
数据范围
- n = target.length \texttt{n} = \texttt{target.length} n=target.length
- 1 ≤ n ≤ 10 5 \texttt{1} \le \texttt{n} \le \texttt{10}^\texttt{5} 1≤n≤105
- targeti \texttt{targeti} targeti 为 '0' \texttt{`0'} '0' 或 '1' \texttt{`1'} '1'
解法
思路和算法
对于长度为 n n n 的字符串,当翻转以下标 i i i 开始的后缀时,下标范围 i , n − 1 i, n - 1 i,n−1 中的所有字符都会翻转。下标 j j j 处的字符的翻转次数等于开始下标小于等于 j j j 的后缀的翻转次数,翻转结果与翻转顺序无关,因此可以从左到右遍历字符串,计算最少翻转次数。
对于以下标 i i i 开始的后缀,如果将该后缀翻转两次,则翻转前后的字符串相同。为了使翻转次数最少,应满足对于每个下标开始的后缀至多翻转一次,并且只有当必须翻转的时候才执行翻转。
由于下标 0 0 0 的左侧没有其他字符,因此判断以下标 0 0 0 开始的后缀的依据是 target 0 \textit{target}0 target0。如果 target 0 = '1' \textit{target}0 = \text{`1'} target0='1',则需要翻转以下标 0 0 0 开始的后缀,否则不需要翻转以下标 0 0 0 开始的后缀。
按照从左到右的顺序遍历字符串并翻转后缀,用 index \textit{index} index 表示最后一次翻转的后缀的开始下标,则不存在任何一个开始下标大于 index \textit{index} index 的后缀被翻转,因此下标范围 index , n − 1 \\textit{index}, n - 1 index,n−1 中的所有字符都相同。遍历过程中如果发现 target \textit{target} target 的两个相邻字符不同,即存在 i > 0 i > 0 i>0 且 target i ≠ target i − 1 \textit{target}i \ne \textit{target}i - 1 targeti=targeti−1,则需要翻转以下标 i i i 开始的后缀,否则字符串 s s s 的下标 i i i 和 i − 1 i - 1 i−1 处的字符相同,不可能满足 s s s 与 target \textit{target} target 相等。
根据上述思路,首先判断以下标 0 0 0 开始的后缀是否需要翻转,然后从左到右遍历 target \textit{target} target,当遇到 target \textit{target} target 的两个相邻字符不同时需要执行一次翻转,遍历结束时即可得到最少翻转次数。
上述思路为贪心策略,贪心策略的正确性说明如下。
-
翻转后满足 s 0 = target 0 s0 = \textit{target}0 s0=target0,且对于任意 0 < i < n 0 < i < n 0<i<n,当 target i = target i − 1 \textit{target}i = \textit{target}i - 1 targeti=targeti−1 时 s i = s i − 1 si = si - 1 si=si−1,当 target i ≠ target i − 1 \textit{target}i \ne \textit{target}i - 1 targeti=targeti−1 时 s i ≠ s i − 1 si \ne si - 1 si=si−1,因此翻转之后 s s s 与 target \textit{target} target 相等。
-
对于每个下标开始的后缀至多翻转一次。
-
对于 i = 0 i = 0 i=0,只有当 s i ≠ target i si \ne \textit{target}i si=targeti 时才翻转以下标 i i i 开始的后缀;对于 i > 0 i > 0 i>0,只有当 target i ≠ target i − 1 \textit{target}i \ne \textit{target}i - 1 targeti=targeti−1 时才翻转以下标 i i i 开始的后缀。每次翻转都是必不可少的,如果在需要翻转的下标处不翻转,则一定有 s 0 ≠ target 0 s0 \ne \textit{target}0 s0=target0 或者 s s s 的相邻下标字符的关系与 target \textit{target} target 的对应相邻下标字符的关系不同,不可能满足 s s s 与 target \textit{target} target 相等。因此贪心策略可以确保得到最少翻转次数。
代码
java
class Solution {
public int minFlips(String target) {
int flips = 0;
char prev = '0';
int n = target.length();
for (int i = 0; i < n; i++) {
char curr = target.charAt(i);
if (curr != prev) {
flips++;
prev = curr;
}
}
return flips;
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 target \textit{target} target 的长度。需要遍历字符串一次计算最少反转次数。
-
空间复杂度: O ( 1 ) O(1) O(1)。