题意
给你一个01构成的数组。请你找出最小翻转步数,使得数组满足以下规则:
1的后面可以是1或者0,但是0的后面必须是0。
样例
给出 array = [1,0,0,1,1,1] , 返回2。
解释:
把两个0翻转成1。
给出 array = [1,0,1,0,1,0] , 返回2。
解释:
把第二个1和第三个1都翻转成0。
注意事项
输入的数组长度n <= 100000
1.解题思路
这道题是一道非常简单的动态规划题。不得不欣慰,自己花了不到20分钟的事件,把这道题做出来了,自己的动态规划终于好了那么一点点了!
由于这道题非常的简单,这里我简单的介绍一下这道题的思路。假设dp[nums.length][2],其中dp[i][0],表示第i张牌变成0需要的最小步数,dp[i][1]意思也是如此。
其中我们从题意中得到,1只能在1后面的,不能再0的后面。所以当nums[i] =1,dp[i][1] = dp[i - 1][1]这个肯定是正确的,但是dp[i ][0],由于nums为1,所以变为0需要需要旋转一次。从而得知,dp[i][0] = Math.min(dp[i - 1][1] + 1, dp[i - 1][0] + 1),首先从0到1,肯定会增加一步;其次0可以在1或者0的后面,所以,需要从上一步中取最小。
当nums[i]= 0时,我们知道的值0可以在1或者0的后面,所以,dp[i][0] = Math.min(dp[i - 1][0], dp[i - 1][1]);同时我们还知道,1只能在1的后面,所以dp[i][1] = dp[i -1] + 1,这里之所以+1是因为nums[i]本来为1,要想变为dp[i][0]需要旋转一步。
2.代码
public int flipDigit(int[] nums) {
int dp[][] = new int[nums.length][2];
if (nums[0] == 1) {
dp[0][1] = 0;
dp[0][0] = 1;
} else {
dp[0][0] = 0;
dp[0][1] = 1;
}
for (int i = 1; i < nums.length; i++) {
if (nums[i] == 1) { //当nums[i] = 1时
//从1 变为0需要增加一步,同时0可以在1或者0的后面,所以需要取最小值
dp[i][0] = Math.min(dp[i - 1][1] + 1, dp[i - 1][0] + 1);
//不变,继承上一步
dp[i][1] = dp[i - 1][1];
} else {
//0可以在1或者0的后面,由于它本身就是0,所以不需要增加步数
dp[i][0] = Math.min(dp[i - 1][0], dp[i - 1][1]);
//从0变为1需要增加步数
dp[i][1] = dp[i - 1][1] + 1;
}
}
return Math.min(dp[nums.length - 1][0], dp[nums.length - 1][1]);
}
网友评论