Java 算法 - 数字翻转(动态规划)

题意

给你一个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]);
    }

你可能感兴趣的:(Java 算法 - 数字翻转(动态规划))