首页 > 试题广场 >

小美的01串翻转

[编程题]小美的01串翻转
  • 热度指数:1423 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小美定义一个 01 串的权值为:每次操作选择一位取反,使得相邻字符都不相等的最小操作次数。
例如,"10001"的权值是 1,因为只需要修改一次:对第三个字符取反即可。
现在小美拿到了一个 01 串,她希望你求出所有非空连续子串的权值之和,你能帮帮她吗?

输入描述:
一个仅包含'0'和'1'的字符串,长度不超过 2000。


输出描述:
所有非空子串的权值和。
示例1

输入

10001

输出

8

说明

长度为 2 的子串中,有 2 个"00"的权值是 1。
长度为 3 的 3 个子串权值都是 1。
长度为 4 的 2 个子串权值都是 1。
长度为 5 的 1 个子串权值是 1。
总权值之和为 2+3+2+1=8

1 分析

首先,给定一个字符串 s, 当小美执行完最少的操作次数后,目标字符串的形式要么是target = "101010...",要么是target = "010101..."

例如,对于字符串 s = "10001",经过一次操作(中间的 0 -> 1)后,目标字符串为 "target = "10101"",这既是上述的第一种目标字符串形式。

因此,我们可以初始化两个和输入字符串长度相同的两种可能目标字符串,对于上例,初始化的目标字符串为 s1 = "10101", s2 = "01010",然后将每一个子串分别与s1s2对比,不同字符的个数既是所需要的操作数,对于例子,与s1不同字符的个数count1 = 1, 与s2不同字符的个数count2 = 4, 最后取 min(count1, count2) 即是输入字符串s01翻转所需的最小操作数(权值)。

对于该题,可以将输入字符串s的每一个非空子串都与可能的目标字符串target比对求出每个非空字串的权值,然后分别相加既是所有非空子串的权值和。但是使用这种暴力解法的话会超时,因此需要我们进一步思考,简化算法流程。


为便于理解,首先,我们画个表table来表示输入字符串s = “10001”的各个非空子串的权值。

1 0 0 0 1
0 1 2 3 4
0 0 1 1 1
1 1 1 1
2 1 1
3 0
4

上表中,table(i,j)表示输入字符s的子串s[i:j]的权值,如table(0, 2) = 1 表示s[0:2] = "100"的权值。

通过观察这张表,可以发现暴力解法存在重复的计算过程,举个例子,比如在计算s的子串 subs = "1000"的权值时,我们已经计算过subs的子串subsubs = "100"的权值,这就造成了一种计算资源的浪费。如果我们把subsubs = "100"的权值计算完后保存了下来,这里为1, 那么,当我们遇到字符串 subs = "1000"时,只需要比较最后多出来的一位是否与可能的目标字符串相同即可,如果相等,则subs = "1000"的权值为subsubs = "100"的权值 +1,否则等于subsubs = "100"的权值。

进一步考虑,因为给定字符串s的目标字符串可能是0101..1010...的形式,我们事先并不知道,因此,我们需要保存字符串s两种可能目标字符串的权值。

具体做法为:

  • 1 给定输入字符串 s,初始化两种可能的目标字符串s1="1010..."s2="0101..."
  • 2 初始化一个存储s不同起始点开始包含的子串的可能权值 vector<vector<int>> nums(n, vector<int>(2, 0))[^1],n=s.length();
  • 3 按输入字符的起始索引开始遍历求解当前起始索引的所有子串的权值和

以上面的表为例,输入为s="10001",具体的执行过程为:

  • 1 初始化,目标子串 s1 = "10101", s2= "01010";
  • 2 初始化, vector<vector<int>> nums(n, vector<int>(2, 0))
  • 3 计算(伪代码),首先,字符起始索引为 0
    s = "10001";
    s1 = "10101";
    s2 = "01010";
    res = 0;
    /*从上表可以看出,
    以0为起始索引的字符字串包括:
    10,100,1000,10001*/
    for i = 0 to 4 {
    for j = i to (i+j < n) {
    /*然后开始与可能目标子串对比*/
    if (s[j] != s1[j]) nums[i][0]++;
    if (s[j] != s2[j]) nums[i][1]++;
    res += min(nums[i][0], nums[i][1]);
    }
    }

在上面的伪代码中,每计算完一个子串的权值,res需要及时累加权值和,思考一下,如果res += min(nums[i][0], nums[i][1])放在第一个for的外面会是什么样的计算结果呢 ?

[^1]: nums[i][0] 计算的是字符串s个位置开始的子串对应目标字符串"1010..."的权值,nums[i][1] 计算的则是对应目标字符串"0101..."的权值.

2 代码

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main() {
    string s;
    cin >> s;

    int res = 0, n = s.length();
    // s1 101010..., s2 010101...
    string s1 = "", s2 = "";
    vector<vector<int>> nums(n-1, vector<int>(2, 0));
    for (int i = 0; i <= n/2; ++i) {
        s1 += '1'; s1 += '0';
        s2 += '0'; s2 += '1';
    }
    for (int i = 0; i < n -1; ++i) {
        for (int j = i; j < n; ++j) {
            if (s[j] != s1[j]) nums[i][0]++;
            if (s[j] != s2[j]) nums[i][1]++;
            res += min(nums[i][0], nums[i][1]);
        }
    }

    printf("%lld\n", res);
}
// 64 位输出请用 printf("%lld")
发表于 2023-09-24 20:14:11 回复(0)
#include <iostream>
using namespace std;



int main() {
    /*
     思路:
     最小操作次数的求法
     一个串要么010101要么101010所以最小操作次数就可以通过两次比对来求得

     子串的求法,进行一个遍历吧就

    n^3的时间复杂度,空间复杂度o(n)
     超时!

     2.思路
     子串的最优解与长度+1子串的最优解有关系吗?
     有关系!且结果为最优解或最优解+1
     所以先求长度为2的子串的权值再往外拓展
     
     对于子串(i,j)只需要比对(i,j-1)并进行增加操作 
     比较两个串0101与1010,求出比对最小值即可,随后保存去比较更长子串

    二维数组动态规划?行!我保存各个子串的权值,保存完再一遍遍历求和。
    需要两个数组,否则不能确保当前匹配的是0开头还是1开头。麻烦
    直接用两个变量保存呢?
    若能证明:子串(i,j)是否只用考虑子串(i,j-1)而不用考虑子串(i+1,j)
    首先其相同部分(i+1,j-1)为固定权值为k;
    对相同部分拓展发现无论i,j位置元素如何,再同一比对下最终其权值都会相同,所以可行

    n方时间复杂度
    
    */

    int res = 0;

    //获取输入
    string str;
    cin >> str;

    //由0开始的和由1开始的
    int start0,start1;



    //所有的长度至少为2的子串
    for(int i = 0; i <str.size()-1;i++)
    {
        start0 = 0,start1 = 0;

        //对于start0来说2的整数倍的地方应该为0,对于start1来说为1
        if(i%2==0) (str[i]=='0')?start1++:start0++; 
        else (str[i]=='0')?start0++:start1++;

        for(int j = i + 1; j < str.size();j++)
        {
            if(j%2==0) (str[j]=='0')?start1++:start0++; 
            else (str[j]=='0')?start0++:start1++;
            
            //子串权值求和
            res += (start0>start1)?start1:start0;

        }
    }


    cout<<res;
    return 0;

}

// 64 位输出请用 printf("%lld")

发表于 2023-09-05 16:54:00 回复(1)
import java.util.*;

public class Main {
    static boolean isAchieved;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        char[] chars = sc.next().toCharArray();
        int n = chars.length;
        int[][][] dp = new int[n][n][2];
        int res = 0;
        dp[0][0][chars[0] - '0'] = 0;
        dp[0][0][1 - chars[0] + '0'] = 1;
        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                if (i == 0 && j == 0) continue;
                int bit = chars[j] - '0';
                dp[i][j][bit] = dp[i][j - 1][1 - bit];
                dp[i][j][1 - bit] = dp[i][j - 1][bit] + 1;
                res += Math.min(dp[i][j][bit], dp[i][j][1 - bit]);
            }
        }
        System.out.println(res);
    }
}

发表于 2023-08-25 14:20:35 回复(0)
strs = input().strip()
n = len(strs)

res = 0
for i in range(n):
    # c0表示当前以i开头的字串,变换后第一个字符为0,需要的变换次数
    # c1表示当前以i开头的字串,变换后第一个字符为1,需要的变换次数
    c0, c1 = 0, 0
    for j in range(i, n):
        if (strs[j] == '1' and (j - i) % 2 == 1)&nbs***bsp;(strs[j] == '0' and (j - i) % 2 == 0):
            c1 += 1
        else:
            c0 += 1
        res += min(c0, c1)
print(res)

发表于 2023-09-03 12:13:27 回复(2)
dp解决,字符串只可能有0或者1结尾两种情况
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        int len = str.length();
        int res = 0;
        int[] lastDpEnd0 = new int[len];
        int[] lastDpEnd1 = new int[len];
        for (int i = 0; i < len; i++) {
            char c = str.charAt(i);
            if (c == '0') {
                lastDpEnd1[i] = 1;
            } else {
                lastDpEnd0[i] = 1;
            }
        }
        for (int k = 2; k <= len; k++) {
            for (int i = 0; i <= len - k ; i++) {
                char c = str.charAt(i + k - 1);
                int temp0 = lastDpEnd0[i];
                int temp1 = lastDpEnd1[i];
                if (c == '0') {
                    lastDpEnd0[i] = temp1;
                    lastDpEnd1[i] = temp0 + 1;
                } else {
                    lastDpEnd1[i] = temp0;
                    lastDpEnd0[i] = temp1+ 1;
                }
                res += Math.min(lastDpEnd0[i], lastDpEnd1[i]);
            }
        }
        System.out.println(res);
    }
}

发表于 2023-08-25 17:14:57 回复(3)

python版本

dp思路大差不差,但是优化代码实在是头疼,从超时到刚好,再到快速计算花了好久时间

超时→不超时1500ms

dp从列表中n个1*2修改为列表中2个1*n
st = list(map(int, input().strip()))
dp = [list(st), [int(i!=1) for i in st]]

res = 0

while len(dp[0])>1:
    dp = [dp[1][:-1], dp[0][:-1]]
    
    for idx, i in enumerate(st[-len(dp[0]):]):
        dp[int(i==0)][idx] += 1

    res += sum([min(i, j) for i, j in zip(dp[0], dp[1])])


print(res)

不超时→快速1000ms

st = list(map(int, input().strip()))
dp = [st, list(map(int, map(lambda x: x==0, st)))]
addtiton = dp.copy()
res = 0

def dp_add(dp1, dp2):
    return [[x + y for x, y in zip(row1, row2)] for row1, row2 in zip(dp1, dp2)]
     
while len(dp[0])>1:
    addtiton = [addtiton[0][1:], addtiton[1][1:]]
    dp = dp_add([dp[1][:-1], dp[0][:-1]], addtiton)
    res += sum([min(i, j) for i, j in zip(dp[0], dp[1])])

print(res)


编辑于 2023-12-02 02:00:19 回复(2)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        String s = in.next();
        char[] array = s.toCharArray();
        int n = s.length();
        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){
                    if(array[i]=='0'){
                        dp[i][i][1]=1;
                    }else{
                        dp[i][i][0]=1;
                    }
                }else{
                    int a = array[j]=='0'? 0:1;
                    dp[i][j][0]=dp[i][j-1][1]+a;
                    dp[i][j][1]=dp[i][j-1][0]+1-a;
                }
            sum+=Math.min(dp[i][j][0],dp[i][j][1]);
            }
        }
        System.out.println(sum);
    }
}
发表于 2023-09-08 15:15:21 回复(0)
dp d的脑壳疼
import java.util.Scanner;
import java.io.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    static String str;
    static int ans, len;
    static char[] arr;
    // dp[i][j][k] 表示 子串为arr[i...j], 且j位置取k时的权值
    static int[][][] dp = new int[2000][2000][2];
    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        while((str = br.readLine()) != null){
            // 一个长度为i的字符串 要吗变成 0101... 要吗变成1010... ;子串的末尾位置只能取 0 或 1
            // 循环遍历 + dp >> 时间复杂度 O(n²)
            len = str.length();
            arr = str.toCharArray();
            // 初始化 i = j 对角线;
            for(int i = 0; i < len; i++){
                dp[i][i][0] = ((arr[i] == '0') ? 0 : 1);
                dp[i][i][1] = ((arr[i] == '1') ? 0 : 1);
            }
            
            for(int i = 0; i < len - 1; i++){
                for(int j = i + 1; j < len; j++){
                    if(arr[j] == '0'){
                        dp[i][j][0] = dp[i][j - 1][1];
                        dp[i][j][1] = 1 + dp[i][j - 1][0];
                    } else { // arr[j] == '1'
                        dp[i][j][0] = dp[i][j - 1][1] + 1;
                        dp[i][j][1] = dp[i][j - 1][0];
                    }
                    
                }
            }
            ans = 0;
            // 取最小 >> 权值 >> 累加
            for(int i = 0; i < len - 1; i++){
                for(int j = i + 1; j < len; j++){
                    ans += Math.min(dp[i][j][0], dp[i][j][1]);
                }
            }
            out.print(ans);
        }
        out.flush();
        out.close();
    }
}

发表于 2023-08-26 17:43:38 回复(0)
有问题,暂时不知bug
#include <iostream>
#include <vector>
using namespace std;
 
intmain() {
    string s;
    intsum=0;
    cin>>s;
    vector<vector<int>> dp(s.size()+1,vector<int>(s.size(),0));
    for(inti=1;i<s.size();i++){
        if(s[i-1]==s[i]){
            dp[2][i-1]=1;
        }
    }
    for(inti=3;i<=s.size();i++){
        for(intj=0;j<s.size()-i+1;j++){
            if(s[j+i-2]==s[j+i-1]&&s[j+i-3]!=s[j+i-1]){
                dp[i][j]=dp[i-1][j]+1;
            }
            elseif(i>=4&&s[j+i-2]==s[j+i-1]&&s[j+i-3]==s[j+i-1]&&s[j+i-4]==s[j+i-1]){
                dp[i][j]=dp[i-1][j]+1;
            }
            else{
                dp[i][j]=dp[i-1][j];
            }
        }
    }
    for(inti=2;i<s.size()+1;i++){
        for(intj=0;j<s.size();j++){
            sum+=dp[i][j];
        }
    }
    cout<<sum<<endl;
}
发表于 2023-08-23 19:13:52 回复(0)
import java.util.*;
import java.io.*;


// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String line = bf.readLine();
        int res=0, n= line.length();
        int[][][] dp = new int[n][n][2];//dp[i][j][m] 数组[i,j]要变成以m结尾的01串,所需的修改次数,m=0/1
        for(int i=0;i<n;i++){
            //len=1
            if(line.charAt(i)=='0'){
                dp[i][i][0]=0;
                dp[i][i][1]=1;
            }
            else{
                dp[i][i][0]=1;
                dp[i][i][1]=0;
            }
            
            for(int j=i+1;j<n;j++){
                dp[i][j][0]= dp[i][j-1][1] + (line.charAt(j)=='0' ? 0 : 1);
                dp[i][j][1]= dp[i][j-1][0] + (line.charAt(j)=='0' ? 1 : 0);
            }
        }

        // for(int i=0;i<n;i++){
        //     for(int j=i;j<n;j++){
        //         System.out.println("dp["+i+"]["+j+"][0]=" + dp[i][j][0]);
        //         System.out.println("dp["+i+"]["+j+"][1]=" + dp[i][j][1]);
        //     }
        // }

        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                int curr = Math.min(dp[i][j][0], dp[i][j][1]);
                res +=curr;
            }
        }

        System.out.println(res);


        
    }
}

发表于 2024-09-01 17:27:52 回复(0)
没想到怎么用动态规划,用的前缀和:

import java.util.*;
import java.io.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
    public static PrintWriter stdOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

    public static void main(String[] args) throws IOException{
        String str = stdIn.readLine().trim();

        int len = str.length();
        int res = 0;
        int[] preSum1 = new int[len + 1];
        int[] preSum2 = new int[len + 1];

        for (int i = 0 ; i < len; i++){
            if (i % 2 == 1){
                if (str.charAt(i) != '1') preSum1[i + 1]++;
                else preSum2[i + 1]++;
            } else {
                if (str.charAt(i) != '0') preSum1[i + 1]++;
                else preSum2[i + 1]++;
            }

            preSum1[i + 1] = preSum1[i + 1] + preSum1[i];
            preSum2[i + 1] = preSum2[i + 1] + preSum2[i];
        }

        for (int i = 2; i <= len; i++){
            for (int j = 0; j <= len - i; j++){
                int cnt1 = preSum1[j + i] - preSum1[j];
                int cnt2 = preSum2[j + i] - preSum2[j];
                res += Math.min(cnt1, cnt2);
            }
        }

        stdOut.println(res);

        stdOut.flush();
    }
}





发表于 2024-08-10 20:15:45 回复(0)
package main
 
import (
    "bufio"
    "fmt"
    "os"
)
 
func main() {
    sc := bufio.NewScanner(os.Stdin)
    buf := make([]byte, 0, 64*1024)
    // 增加能输入的一行的最大字符数量
    sc.Buffer(buf, 1024*1024)
    sc.Scan()
    s := sc.Text()
    res := 0
    n := len(s)
    // 101010...
    for i := 0; i < n-1; i++ {
        var pre int
        for j := i; j < n; j++ {
            switch (j - i) & 1 {
            case 1:
                if s[j] == '1' {
                    pre++
                }
            case 0:
                if s[j] == '0' {
                    pre++
                }
            }
            res += min(pre, j-i+1-pre)
        }
    }
    fmt.Println(res)
}
 
func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}
看了@cx_333大佬的思路做出来的,做了一些空间上的优化:
1. 没有真的把模式串算出来,只需要根据s[i...j]中j相对i的位数是奇数位还是偶数位判断
2. 没有用数组记录每个子串的权值,zero和one的权值和一定等于s[i..j]的长度,所以只需要维护其中一个

编辑于 2024-03-06 09:44:47 回复(0)

1、定义两个个数组记录如果全部修改为 0101 或 1010,需要修改的位置,1表示需要修改,0表示不需要修改

let s = "0110";
let zeroList = [0,0,1,1]; // => 0101
let oneList = [1,1,0,0]; // => 1010

2、开始计算两个三个字符时需要修改几个字符

let s = "0110";
let newZeroList = [0,1,2]; // => "01","10","01"
let newOneList = [2,1,0]; // => "10","01","10"

然后遍历 newZeroList 和 newOneList 中同一个位置下较小的数加和就是当前长度的权值。

例如
zOL = [0,1,2]
nOL = [2,1,0]
=>[0,1,0] => 权值为 0+1+0=1

3、循环第二步直到长度为 s.length

第二步的迭代过程(zero为例)

图片说明

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void async function () {
    // Write your code here
    while(line = await readline()){
        solu(line);
    }
}()
function solu(str) {
    let list = str.split('').map(_ => _);
    let len = str.length;
    let zeroList = [];
    let oneList = [];
    let bit = 0;
    for (let i = 0;i < len;i++) {
        if (list[i] == bit) {
            zeroList.push(0);
            oneList.push(1);
        } else {
            zeroList.push(1);
            oneList.push(0);
        }
        bit = 1 - bit;
    }
    let newZeroList = [];
    let newOneList = [];
    let sum = 0;
    for (let i = 1;i < len;i++) {
        newZeroList.push(zeroList[i - 1] + zeroList[i]);
        newOneList.push(oneList[i - 1] + oneList[i]);
    }
    sum += calc(newZeroList, newOneList, len - 1);
    for (let p = 2;p < len;p++) {
        for (let i = 0;i < len - p;i++) {
            newZeroList[i] += zeroList[i + p];
            newOneList[i] += oneList[i + p];
        }
        sum += calc(newZeroList, newOneList, len - p);
    }
    console.log(sum);
}
function calc(list1, list2, len) {
    // console.log(list1, list2, len);
    let s = 0;
    for (let i = 0;i < len;i++) {
        s += Math.min(list1[i], list2[i]);
    }
    return s;
}
发表于 2023-12-28 17:58:16 回复(0)
DP
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        char[] s = in.next().toCharArray();
        int n = s.length;
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            int[] dp = new int[2];
            dp[1] = 1;    // 最后一个位置反转了
            for (int j = i + 1; j < n; ++j) {
                if (s[j] == s[j - 1]) {
                    int t = dp[0];
                    dp[0] = dp[1];
                    dp[1] = 1 + t;
                } else {
                    dp[0] = dp[0];
                    dp[1] = 1 + dp[1];
                }
                ans += Math.min(dp[0], dp[1]);
            }
        }
        System.out.println(ans);
    }
}


编辑于 2023-12-26 21:00:41 回复(0)
dp[i][j] 表示如果把 子字符串 [i,j] 奇数位填0, 偶数位填1需要修改的数量。 那么把[i,j] 变为01串需要的操作就是 min(j-i+1-dp[i][j], dp[i][j]). 
那么直接通过矩阵递推填满整个矩阵即可。
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        String st = in.nextLine();
        char[] ss = st.toCharArray();
        int n = ss.length;
        // "1": 1; "0": 0
        // ss[i][j], [i, j]
        int[][] weight = new int[n][n];
        for (int i = 0; i < n; i++) {
            if (i % 2 == 1) {
                weight[i][i] = ss[i]=='1' ? 1: 0;
            } else {
                weight[i][i] = ss[i]=='0' ? 1: 0;
            }
        }
        int res = 0;
        for (int i = 2; i  <= n; i ++) {
            for (int j = 0; j + i - 1 < n; j++) {
                weight[j][j+i-1] = weight[j][i+j-2] + weight[j+i-1][j+i-1];
                res += Math.min( i-weight[j][j+i-1], weight[j][j+i-1]);
            }
        }
        System.out.println(res);
    }
}


编辑于 2023-12-26 18:53:42 回复(0)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // s = 0:  dp[i][j][1] = dp[i][j][0] + 1; dp[i][j][0] = dp[i][j][1];
        // s = 1:  dp[i][j][0] = dp[i][j][1] + 1; dp[i][j][0] = dp[i][j][0];
        String str = in.nextLine();
        int len = str.length();
        int[][][] dpList = new  int[len][len][2];
        for (int i = 0; i < len; i++) {
            if (str.charAt(i) == '0') {
                dpList[i][i][0] = 0;
                dpList[i][i][1] = 1;
            } else {
                dpList[i][i][0] = 1;
                dpList[i][i][1] = 0;
            }
        }
        int sum = 0; 
        for (int i = 0; i < len; i++) {
            for (int j = i + 1 ; j < len; j++) {
                if (str.charAt(j) == '0') {
                    dpList[i][j][0] = dpList[i][j-1][1];
                    dpList[i][j][1] = dpList[i][j-1][0] + 1;
                } else {
                    dpList[i][j][0] = dpList[i][j-1][1] +1 ;
                    dpList[i][j][1] = dpList[i][j-1][0];
                }
                sum += Math.min(dpList[i][j][0], dpList[i][j][1]);
            }
        }
        System.out.println(sum);

    }
}


发表于 2023-10-31 00:48:33 回复(0)
strs = list(map(int, input()))
n = len(strs)
 
res = 0
for i in range(n):
    # c0表示strs[i:j + 1]字串,以0开头的最少变换次数
    # c0表示strs[i:j + 1]字串,以1开头的最少变换次数
    c0, c1 = 0, 0
    for j in range(i,n):
        length = j - i - 1
        if (not strs[j] and length % 2 == 0)&nbs***bsp;(strs[j] and length % 2 == 1):
            # 以0开头长度为偶数的交替字符串最后一位必须为1
            # 以1开头长度为奇数的交替字符串最后一位必须为0
            c0 += 1
        else:
            c1 += 1
        print(i,j,strs[i:j + 1],c0,c1)
        res += min(c0, c1)
print(res)

发表于 2023-09-21 13:44:00 回复(1)
#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main() {
    string s;
    cin >> s;
    int n = s.size();
    int result = 0;
    //vector<vector<int>> dp(n, vector<int>(n));
    int a = 0, b = 0;
    for(int i = 0; i < n; i++){
        if(s[i] == '0'){
            a = 0;
            b = 1;
        }
        else{
            a = 1;
            b = 0;
        }
        //cout << "a = " << a << "b = " << b << "\t";
        for(int j = i + 1; j < n; j++){
            int tmp = a;
            if(s[j] == '0'){
                a = b;
                b = tmp + 1;
            }
            else{
                a = b + 1;
                b = tmp;
            }
            // cout << min(a, b) << " ";
            //cout << "a = " << a << "b = " << b << "\t";
            result += min(a, b);
        }
        //cout << endl;
    }
    cout << result << endl;
}
发表于 2023-09-06 09:44:25 回复(0)
        import java.util.Scanner;

        public class Main {

            public static void main(String[] args) {

                Scanner in = new Scanner(System.in);

                String s = in.next();

                int sum = getNum(s);

                System.out.println(sum);

            }

            public static int getNum(String s) {

                int n = s.length();

                StringBuffer sb1 = new StringBuffer();

                StringBuffer sb2 = new StringBuffer();

                //sb1表示101010101...即以1开头的标准01串

                //sb2表示010101010...即以0开头的标准01串

                for (int i = 0; i < n; i++) {

                    sb1.append((i+1)%2);

                    sb2.append(i%2);

                }

                int sum = 0;

                //dp1[i][j]表示s.substring(i,j+1)这个子串根据sb1.substring(i,j+1)得到的权重值

                //dp2[i][j]表示s.substring(i,j+1)这个子串根据sb2.substring(i,j+1)得到的权重值

                //s.substring(i,j+1)这个子串的权重值取dp1[i][j]和dp2[i][j]的最小值

                /**举例:对于1000这个串,根据1010得到的权重是1;根据0101得到的权重是3;最后权重取最小值为1

                 */

                int dp1[][] = new int[n][n];

                int dp2[][] = new int[n][n];

                for (int i = 0; i < n ; i++) {

                    for (int j = i ; j < n; j++) {

                        if (j == i ) {

                            dp1[i][j] = s.charAt(i) == sb1.charAt(i) ? dp1[i][j] : 1;

                            dp2[i][j] = s.charAt(i) == sb2.charAt(i) ? dp2[i][j] : 1;

                            sum = sum + Math.min(dp1[i][j], dp2[i][j]);

                            continue;

                        }

                        dp1[i][j] = dp1[i][j - 1];

                        dp2[i][j] = dp2[i][j - 1];

                        if (s.charAt(j) != sb1.charAt(j)) {

                            dp1[i][j] ++;

                        }

                        if (s.charAt(j) != sb2.charAt(j)) {

                            dp2[i][j] ++;

                        }

                        sum = sum + Math.min(dp1[i][j], dp2[i][j]);

                    }

                }

                return sum;

            }

        }
发表于 2023-08-31 14:16:38 回复(0)
发表于 2023-08-25 11:08:00 回复(1)