首页 > 试题广场 >

小美的01串翻转

[编程题]小美的01串翻转
  • 热度指数:1477 时间限制: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

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)