动态规划典型题目:01串反转最小操作数(求权值)

 题目描述:

小美定义一个 01 串的权值为:每次操作选择一位取反,使得相邻字符都不相等的最小操作次数。
例如,"10001"的权值是 1,因为只需要修改一次:对第三个字符取反即可。
现在小美拿到了一个 01 串,她希望你求出所有非空连续子串的权值之和,你能帮帮她吗?

新手菜鸟,做这道题花了很多时间,参考了不少的思路,写下自己的理解,做个总结,希望对大家有帮助

import java.util.*;

/*
*动态规划类型
*
* 小美定义一个 01 串的权值为:每次操作选择一位取反,使得相邻字符都不相等的最小操作次数。
例如,"10001"的权值是 1,因为只需要修改一次:对第三个字符取反即可。
现在小美拿到了一个 01 串,她希望你求出所有非空连续子串的权值之和,你能帮帮她吗?
*/


public class StringReverse {
    public static void stringRe(){
        Scanner in = new Scanner(System.in);

        String s = in.next();
        char[] array = s.toCharArray();

        int n = s.length();//01串长度
        int[][][] dp = new int[n][n][2];
        int sum = 0;//权值和

        //从结尾开始遍历字符串
        for (int i = n - 1; i >= 0; i--) {
            //从当前字符往后直到结尾(取子串)
            for (int j = i; j < n; j++) {
                if (i == j) {
        /*
       总体思路:dp[j][0]和dp[j][1]分别表示将当前位修改为0和1时的权值和(注意此处说的是修改)。
       所以:
       1、当前位是1时,dp[j][0]中的[0]和dp[j][1]中的[1]也分别表示反转当前数字和不反转当前数字。            
       因为已经是1了,所以修改为0(dp[j][0]=1)表示反转,修改为1(dp[j][1])表示不反转,不用操    
       作

       2、当前位是0时,dp[j][0]中的[0]和dp[j][1]中的[1]分别表示不反转当前数字和反转当前数字。因 
       为已经是0了,所以修改为0(dp[j][0])表示不反转,修改为1(dp[j][1]=1)表示反转
        */
                    if (array[i] == '0') {
                        dp[i][i][1] = 1;
                    } else {
                        dp[i][i][0] = 1;
                    }

                } else {
                    int numFor0 = array[j] == '0' ? 0 : 1;
                    int numFor1 = array[j] == '0' ? 1 : 0;

                    /*状态转移:当前位既然修改为0了,要相邻位不相同,上一位必定要
                     修改为1,所以总的反转次数:递推成上一位取1时的权值
                     再加上当前数字的反转次数(numFor0)
                    */
                    dp[i][j][0] = dp[i][j - 1][1] + numFor0;//当前数是0时的状态转移方程

                    /*状态转移:当前位既然修改为1了,要相邻位不相同,上一位必定要
                     修改为0,所以总的反转次数:递推成上一位取0时的权值
                     再加上当前数字的反转次数(numFor1)
                    */
                    dp[i][j][1] = dp[i][j - 1][0] + numFor1;//当前数是1时的状态转移方程
                }
                sum += Math.min(dp[i][j][0], dp[i][j][1]);//反转次数取最小就是权值
            }
        }
        System.out.println(sum);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值