数组翻转_LintCode 题解|843. 微软高频题:数字翻转

b24a2aab516389e58f376f8d65a87b50.png

LintCode 843. 微软高频题:数字翻转

九章算法 - 帮助更多中国人找到好工作,硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧​www.jiuzhang.com

描述

给定一个01构成的数组。你可以翻转1变成0或者反转0变成1

请问最少反转多少次可以使得数组满足以下规则:

1的后面可以是1或者0,而0的后面必须是0

78b577566e17538feb7dfd4d317b368e.png

样例

样例 1:

输入: [1,0,0,1,1,1]
输出: 2
解释: 把两个0翻转成1。

样例 2:

输入: [1,0,1,0,1,0]
输出: 2
解释: 把第二个1和第三个1都翻转成0。

题解

算法:dp

根据题给的0之后一定是0的条件,我们可以发现,最后通过翻转所形成的数组一定满足111111000000这样的形式,即在若干连续1之后出现若干个连续0(因为0后只能为0)。所以我们可以通过枚举10之间的分界点,依次算出它们的花费,取最小值。

  • 开始统计出所有1的个数。
  • 开始枚举分界点i,认为翻转完成后0~i都为1,i之后都为0
  • 对于上述的数组,计算花费。
  • 花费的内容由两部分构成:
    • i之前为0的,需要转变为1。cost1=i-temp+1 0~i除了0都是1
    • i之后为1的,需要转变为0。cost2=all-temp。即所有的1个数-0~i之间1的个数
  • 对于所有的cost1+cost2 取最小值即可。

复杂度分析

  • 时间复杂度O(n)
    • 枚举了数组的长度
  • 空间复杂度O(1)
    • 消耗了常数的空间
/**
* This reference program is provided by @jiuzhang.com
* Copyright is reserved. Please indicate the source for forwarding
*/

public class Solution {
    /**
     * @param nums: the array
     * @return: the minimum times to flip digit
     */
    int min(int a, int b) {
        if(a > b)
            return b;
        return a;
    }
    public int flipDigit(int[] nums) {
        // Write your code here
        int all = 0, temp = 0, ans;
        for(int i = 0; i < nums.length; i++) {
            if(nums[i] == 1) {
                all++;
            }
        }
        ans = all;
        for(int i = 0; i < nums.length; i++) {
            if(nums[i] == 1) {
                temp++;
            }
            ans = min(ans, all - temp + i - temp + 1);
        }
        return ans;
    }
}

// 九章动态规划专题班版本
public class Solution {
    /**
     * @param nums: the array
     * @return: the minimum times to flip digit
     */
    public int flipDigit(int[] A) {
        int n = A.length;
        if (n <= 1) {
            return 0;
        }
        
        int[][] f = new int[n + 1][2];
        f[0][0] = f[0][1] = 0;
        
        int i, j, k, t;
        for (i = 1; i <= n; ++i) {
            for (j = 0; j < 2; ++j) {
                f[i][j] = Integer.MAX_VALUE;
                t = 0;
                if (j != A[i - 1]) {
                    ++t;
                }
                
                for (k = 0; k < 2; ++k) {
                    if (k == 0 && j == 1) continue;
                    f[i][j] = Math.min(f[i - 1][k] + t, f[i][j]);
                }
            }
        }
        
        return Math.min(f[n][0],f[n][1]);
    }
}
/**
* This reference program is provided by @jiuzhang.com
* Copyright is reserved. Please indicate the source for forwarding
*/

public class Solution {
    /**
     * @param nums: the array
     * @return: the minimum times to flip digit
     */
    public int flipDigit(int[] A) {
        //以0、1结尾的前i个数的最少翻转次数
        int n = A.length;
        int[] zero = new int[n + 1];
        int[] one = new int[n + 1];
        
        //初始化
        zero[0] = one[0] = 0;
        
        int i;
        for (i = 1; i <= n; i++) {
            zero[i] = A[i - 1] == 0 ? Math.min(one[i - 1], zero[i - 1]) : 
                                      Math.min(one[i - 1], zero[i - 1]) + 1;
            one[i] = A[i - 1] == 1 ? one[i - 1] : one[i - 1] + 1;
        }
        return Math.min(zero[n], one[n]);
    }
}

更多大厂高频考题,请点击LintCode进行在线评测

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值