灯泡开关 IV
题目描述
房间中有 n 个灯泡,编号从 0 到 n-1 ,自左向右排成一行。最开始的时候,所有的灯泡都是关着的。
请你设法使得灯泡的开关状态和 target 描述的状态一致,其中 target[i] 等于 1 第 i 个灯泡是开着的,等于 0 意味着第 i 个灯是关着的。
有一个开关可以用于翻转灯泡的状态,翻转操作定义如下:
- 选择当前配置下的任意一个灯泡(下标为 i )
- 翻转下标从 i 到 n-1 的每个灯泡
翻转时,如果灯泡的状态为 0 就变为 1,为 1 就变为 0 。
返回达成 target 描述的状态所需的 最少 翻转次数。
做题之前能快速的理解题意非常重要。先把题目意思看懂,看不懂也不要着急,结合下面的示例看题目意思,相信你能很快理解题目意思。
示例
题目要从一个
"0000.."
翻转成target
,我们用逆向思维,从target
翻转成"0000.."
,这样似乎简单一点。
示例1:
输入:
target = "10111"
输出:3
解释:初始配置 "00000".
从第 3 个灯泡(下标为 2)开始翻转"00000" -> "00111"
从第 1 个灯泡(下标为 0)开始翻转"00111" -> "11000"
从第 2 个灯泡(下标为 1)开始翻转"11000" -> "10111"
至少需要翻转 3 次才能达成 target 描述的状态
示例2:
输入:
target = "101"
输出:3
解释:"000" -> "111" -> "100" -> "101".
示例 3:
输入:
target = "00000"
输出:0
示例 4:
输入:
target = "001011101"
输出:5
这题是有规律的
"101"
和"101111"
的结果是一样的都是3
,"101"
和"100001"
的结果也是一样都是3
,这条规律,我想表达的意思是:在做这道题的时候,连在一起的1
或连在一起的0
都可以视为单个1
或单个0
。这里可以把这个步骤称为简化
"10"
的答案是2
,"1010"
的答案是4
,"101010"
的答案是6
,经过验证,想"1010...10"
这种格式的答案就是其字符串长度
"00101"
和"101"
结果一样都是3,开头的0
可以全部去掉,但结尾的0
就不一样了,"101"
和"1010"
答案不一样。
用以上规律解问题
我举个栗子:"0001011101101"
输入:
"0001011101101"
设置一个全局变量res=0
存放翻转次数
简化:"0001011101101"->"01010101“
,简化步骤不会增加翻转次数。
根据规律3开头的0可以去掉:"01010101“->"1010101“,不会增加翻转次数。
把"1010101“
改成规律2的格式,①"1010101“->"1010100"
,翻转次数+1
,res++
;
②简化"1010100"
->"101010"
,不会增加翻转次数;③根据规律3计算"101010"
翻转成"000000"
需要6步,翻转次数+6
,res+=6
。最终答案就是7。
输出:7
完整代码
class Solution {
public:
int minFlips(string target) {
int res=0;
string s="";//存放简化完成的字符串
//简化过程
for(int i=0;i<target.length()-1;i++){
if(target[i]!=target[i+1]){
s+=target[i];
}
}
s+=target[target.length()-1];
//简化过程
int n=s.length();//获取简化后的字符串长度
cout<<s;
if(s[0]=='0') n-=1;//如果开头为0,去掉开头的0,相当于字符串长度减一
if(s[s.length()-1]=='1'){
res+=1;//将结尾的1翻转成0,翻转次数+1,res++;
n-=1;//这时,结尾有两个0,去掉结尾的一个0,相当于字符串长度减一
}
res+=n;
return res;
}
};