JAVA程序设计:不同的好子序列数目(LeetCode:1987)

给你一个二进制字符串 binary 。 binary 的一个 子序列 如果是 非空 的且没有 前导 0 (除非数字是 "0" 本身),那么它就是一个 好 的子序列。

请你找到 binary 不同好子序列 的数目。

比方说,如果 binary = "001" ,那么所有 好 子序列为 ["0", "0", "1"] ,所以 不同 的好子序列为 "0" 和 "1" 。 注意,子序列 "00" ,"01" 和 "001" 不是好的,因为它们有前导 0 。
请你返回 binary 中 不同好子序列 的数目。由于答案可能很大,请将它对 109 + 7 取余 后返回。

一个 子序列 指的是从原数组中删除若干个(可以一个也不删除)元素后,不改变剩余元素顺序得到的序列。

示例 1:

输入:binary = "001"
输出:2
解释:好的二进制子序列为 ["0", "0", "1"] 。
不同的好子序列为 "0" 和 "1" 。
示例 2:

输入:binary = "11"
输出:2
解释:好的二进制子序列为 ["1", "1", "11"] 。
不同的好子序列为 "1" 和 "11" 。
示例 3:

输入:binary = "101"
输出:5
解释:好的二进制子序列为 ["1", "0", "1", "10", "11", "101"] 。
不同的好子序列为 "0" ,"1" ,"10" ,"11" 和 "101" 。
 

提示:

1 <= binary.length <= 105
binary 只含有 '0' 和 '1' 。

思路:参考:官方题解。考虑采用动态规划,定义dp[i][j]表示前i个字符以数字j为结尾的方案数。难点在于递推过程。考虑以下两种情况:

(1)当前数为1

         由于第i个元素不会对以0结尾的方案数产生贡献,因此f[i][0]=f[i-1][0]

         难点在于以1结尾的方案数如何变化?

         前i个字符以1结尾的方案数主要包括两个部分:前i-1个元素组成以1结尾的方案数以及必须添加第i个字符组成以1结尾的方案数。

         前i-1个元素组成以1结尾的方案数:f[i-1][1]

         必须添加第i个字符组成以1结尾的方案数:f[i-1][0]+f[i-1][1]+1。即前i-1个字符以0结尾并且第i个字符为1;前i-1个字符已经是以1结尾了,并且使用第i个字符;只使用第i个i字符这三种情况。

         我们需要思考这两种方案是否存在重复情况:其实可以证明,第一种方案是第二种方案的子集,详解可以参考官方题解,前边已经贴出链接。

 (2)当前数为0

     递推方式同理。

class Solution {

    private static final int mod = 1000000007;

    public int numberOfUniqueGoodSubsequences(String binary) {
        int n = binary.length();
        int ans = 0;
        if (binary.contains("0"))
            ans = 1;
        int l = binary.indexOf('1');
        if (l == -1)
            return ans;
        int even = 0, odd = 0;
        for (char ch : binary.toCharArray()) {
            if (ch == '0')
                even = (even + odd) % mod;
            else
                odd = (even + odd + 1) % mod;
        }
        ans = (ans + even + odd) % mod;
        return ans;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值