普通视图

发现新文章,点击刷新页面。
今天 — 2026年3月11日LeetCode 每日一题题解

库函数写法(Python/Java/C++/C/Go/JS/Rust)

作者 endlesscheng
2026年3月11日 07:59

题目让我们把 $n$ 取反。

例如二进制 $n=11001$,取反后是 $00110$,即十进制的 $6$。

看上去,计算 ~n 就好了?

但这样做会把更高位的 $0$ 也取反,对于 $32$ 位整数来说,$11001$ 实际是 $00000000000000000000000000011001$,取反后是 $11111111111111111111111111100110$。

所以对于这个例子,要只把 $n$ 的低 $5$ 位取反,也就是计算 $n$ 和 $11111$ 的异或。

$11111$ 怎么算?设 $w=5$ 是 $n$ 的二进制长度,计算 1 << w 可以得到 $100000$,再减去 $1$,得到 $11111$。

特殊情况:根据题意,$n=0$ 反转后是 $1$,如果用库函数算 $n=0$ 的二进制长度,会算出 $0$,这会导致 $n$ 取反后的值是 $0$。所以特判 $n=0$ 的情况,返回 $1$。

###py

class Solution:
    def bitwiseComplement(self, n: int) -> int:
        if n == 0:
            return 1
        w = n.bit_length()
        return ((1 << w) - 1) ^ n

###java

class Solution {
    public int bitwiseComplement(int n) {
        if (n == 0) {
            return 1;
        }
        int w = 32 - Integer.numberOfLeadingZeros(n);
        return ((1 << w) - 1) ^ n;
    }
}

###cpp

class Solution {
public:
    int bitwiseComplement(int n) {
        if (n == 0) {
            return 1;
        }
        int w = bit_width((uint32_t) n);
        return ((1 << w) - 1) ^ n;
    }
};

###c

int bitwiseComplement(int n) {
    if (n == 0) {
        return 1;
    }
    int w = 32 - __builtin_clz(n);
    return ((1 << w) - 1) ^ n;
}

###go

func bitwiseComplement(n int) int {
if n == 0 {
return 1
}
w := bits.Len(uint(n))
return 1<<w - 1 ^ n
}

###js

var bitwiseComplement = function(n) {
    if (n === 0) {
        return 1;
    }
    const w = 32 - Math.clz32(n);
    return ((1 << w) - 1) ^ n;
};

###rust

impl Solution {
    pub fn bitwise_complement(n: i32) -> i32 {
        if n == 0 {
            return 1;
        }
        let w = n.ilog2() + 1;
        ((1 << w) - 1) ^ n
    }
}

复杂度分析

  • 时间复杂度:$\mathcal{O}(1)$。
  • 空间复杂度:$\mathcal{O}(1)$。

专题训练

见下面位运算题单的「一、基础题」。

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

欢迎关注 B站@灵茶山艾府

每日一题-十进制整数的反码🟢

2026年3月11日 00:00

每个非负整数 N 都有其二进制表示。例如, 5 可以被表示为二进制 "101"11 可以用二进制 "1011" 表示,依此类推。注意,除 N = 0 外,任何二进制表示中都不含前导零。

二进制的反码表示是将每个 1 改为 0 且每个 0 变为 1。例如,二进制数 "101" 的二进制反码为 "010"

给你一个十进制数 N,请你返回其二进制表示的反码所对应的十进制整数。

 

    示例 1:

    输入:5
    输出:2
    解释:5 的二进制表示为 "101",其二进制反码为 "010",也就是十进制中的 2 。
    

    示例 2:

    输入:7
    输出:0
    解释:7 的二进制表示为 "111",其二进制反码为 "000",也就是十进制中的 0 。
    

    示例 3:

    输入:10
    输出:5
    解释:10 的二进制表示为 "1010",其二进制反码为 "0101",也就是十进制中的 5 。
    

     

    提示:

    1. 0 <= N < 10^9
    2. 本题与 476:https://leetcode.cn/problems/number-complement/ 相同

    [JAVA] 0ms 100% 做差法 3行代码 时间复杂度O(1)

    作者 Jade_Xie
    2020年12月3日 20:41

    拿到题目先不要急,注意观察。

    示例1:
    输入:5 101
    输出:2 010

    所以本质是 111(7) - 101(5) = 010(2)

    问题转化为:求输入数字N的二进制数长度

    求得N的二进制数长度length后,就可以用长为length,各位均为1的数字减去N,即可得到最终结果

    由于是二进制,所以可以使用 (int) log2(N) + 1来求其长度

    比如5(101)的计算结果为:
    (int) log2(N) + 1 = 2 + 1 = 3

    而长为length,各位均为1的二进制数字的大小是 2 ^ length - 1
    比如111 的大小即为 2^3 - 1 = 7

    所以最终结果便是 2 ^ length - 1 - N

    ###java

    class Solution {
        public int bitwiseComplement(int N) {
    
            //对于0需要单独讨论,因为log(x) 的定义域不包括0
            if(N == 0) return 1;
    
            //java中没有log2(x)函数,默认log以e为底,log10以10为底
            //所以要用换底公式loga(x) / loga(y) = logy(x)
            //所以loge(N) / loge(2) = log2(N)
            int length = (int)(Math.log(N) / Math.log(2)) + 1;
            
            return (int)(Math.pow(2,  length)) - 1 - N;
        }
    }
    

    图片1.png

    两种方法

    作者 keyway1984
    2019年9月1日 00:43

    方法1: 异或运算法

    class Solution {
    public:
        int bitwiseComplement(int N) {
            
            if(N==0)
                return 1;
            
            int temp1 = 1;
            int temp2 = N;
            
            while(temp2>0){//不停用temp1对原整数进行异或运算,每次运算结束后将temp1朝左移动1位
                
                N ^= temp1;
                temp1 = temp1 << 1;
                temp2 = temp2 >> 1;
            }
    
            
            return N;
        }
    };
    

    方法2: 高位差值法

    方法2是看评论学会的,很巧妙~

    class Solution {
    public:
        int bitwiseComplement(int N) {
            
            int temp = 2;
            
            while(temp<=N){
                
                temp = temp << 1;
            }
            
            return temp - N - 1;
            
        }
    };
    
    昨天 — 2026年3月10日LeetCode 每日一题题解

    每日一题-找出所有稳定的二进制数组 II🔴

    2026年3月10日 00:00

    给你 3 个正整数 zero ,one 和 limit 。

    一个 二进制数组 arr 如果满足以下条件,那么我们称它是 稳定的

    • 0 在 arr 中出现次数 恰好 为 zero 。
    • 1 在 arr 中出现次数 恰好 为 one 。
    • arr 中每个长度超过 limit 的 子数组同时 包含 0 和 1 。

    请你返回 稳定 二进制数组的 数目。

    由于答案可能很大,将它对 109 + 7 取余 后返回。

     

    示例 1:

    输入:zero = 1, one = 1, limit = 2

    输出:2

    解释:

    两个稳定的二进制数组为 [1,0] 和 [0,1] ,两个数组都有一个 0 和一个 1 ,且没有子数组长度大于 2 。

    示例 2:

    输入:zero = 1, one = 2, limit = 1

    输出:1

    解释:

    唯一稳定的二进制数组是 [1,0,1] 。

    二进制数组 [1,1,0] 和 [0,1,1] 都有长度为 2 且元素全都相同的子数组,所以它们不稳定。

    示例 3:

    输入:zero = 3, one = 3, limit = 2

    输出:14

    解释:

    所有稳定的二进制数组包括 [0,0,1,0,1,1] ,[0,0,1,1,0,1] ,[0,1,0,0,1,1] ,[0,1,0,1,0,1] ,[0,1,0,1,1,0] ,[0,1,1,0,0,1] ,[0,1,1,0,1,0] ,[1,0,0,1,0,1] ,[1,0,0,1,1,0] ,[1,0,1,0,0,1] ,[1,0,1,0,1,0] ,[1,0,1,1,0,0] ,[1,1,0,0,1,0] 和 [1,1,0,1,0,0] 。

     

    提示:

    • 1 <= zero, one, limit <= 1000

    找出所有稳定的二进制数组 II

    2024年8月5日 11:48

    方法一:记忆化搜索

    思路

    根据稳定数组的前两个条件,可知稳定数组的长度为 $\textit{zero} + \textit{one}$。第三个条件可知,稳定数组不存在长度为 $\textit{limit} + 1$ 的全 $0$ 或全 $1$ 子数组。

    接下来我们分解问题,包含 $\textit{zero}$ 个 $0$ 和 $\textit{one}$ 个 $1$ 的稳定数组,末位元素可能为 $1$,也可能为 $0$。

    • 如果末位元素为 $1$,我们需要知道有多少个包含 $\textit{zero}$ 个 $0$ 和 $\textit{one}-1$ 个 $1$ 的稳定数组,再去掉“由于添加了一个 $1$ 而使得原来的稳定数组变得不稳定”的情况。那么有哪些情况会使得原来稳定的数组变得不稳定呢?即原来的稳定数组的末尾连续 $1$ 的个数正好为 $\textit{limit}$ 个。在这种情况下,添加一个 $1$ 会使得原来稳定的数组变得不稳定。这种情况出现的次数,即为包含 $\textit{zero}$ 个 $0$ 和 $\textit{one}-1-\textit{limit}$ 个 $1$,且末位元素为 $0$ 的稳定数组的个数。
    • 如果末位元素为 $0$,我们需要知道有多少个包含 $\textit{zero}-1$ 个 $0$ 和 $\textit{one}$ 个 $1$ 的稳定数组,再去掉“由于添加了一个 $0$ 而使得原来的稳定数组变得不稳定”的情况。

    这样一来,我们就将问题分解为子问题了,可以用动态规划求解。用函数 $\textit{dp}(\textit{zero},\textit{one},\textit{lastBit})$,来求解包含 $\textit{zero}$ 个 $0$ 和 $\textit{one}$ 个 $1$,并且末位元素为 $\textit{lastBit}$ 的稳定数组的个数,其中 $\textit{lastBit}$ 为 $0$ 或 $1$。根据上面的讨论,可以得到递推公式:

    • $\textit{dp}(\textit{zero},\textit{one},0)$ = $\textit{dp}(\textit{zero}-1,\textit{one},0) + \textit{dp}(\textit{zero}-1,\textit{one},1) - \textit{dp}(\textit{zero}-1-\textit{limit},\textit{one},1)$
    • $\textit{dp}(\textit{zero},\textit{one},1)$ = $\textit{dp}(\textit{zero},\textit{one}-1,0) + \textit{dp}(\textit{zero},\textit{one}-1,1) - \textit{dp}(\textit{zero},\textit{one}-1-\textit{limit},0)$。

    另外考虑边界情况。如果 $\textit{zero}$ 为 $0$,那么当 $\textit{lastBit}$ 为 $1$ 或者 $\textit{one}$ 大于 $\textit{limit}$ 时,不存在这样的稳定数组,返回 $0$,否则返回 $1$。如果 $\textit{zero}$ 为 $1$,也有对应的结论。

    我们用记忆化搜索的方式来计算结果,记录所有的中间状态,最终返回 $\textit{dp}(\textit{zero},\textit{one},0)$ + $\textit{dp}(\textit{zero},\textit{one},1)$ 取模后的结果。

    代码

    ###Python

    class Solution:
        def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:
            mod = 10 ** 9 + 7
    
            @cache
            def dp(zero, one, lastBit):
                if zero == 0:
                    if lastBit == 0 or one > limit:
                        return 0
                    else:
                        return 1
                elif one == 0:
                    if lastBit == 1 or zero > limit:
                        return 0
                    else:
                        return 1
                if lastBit == 0:
                    res = dp(zero - 1, one, 0) + dp(zero - 1, one, 1)
                    if zero > limit:
                        res -= dp(zero - limit - 1, one, 1)
                else:
                    res = dp(zero, one - 1, 0) + dp(zero, one - 1, 1)
                    if one > limit:
                        res -= dp(zero, one - limit - 1, 0)
                return res % mod
                
            res = (dp(zero, one, 0) + dp(zero, one, 1)) % mod
            dp.cache_clear()
            return res
    

    ###C++

    class Solution {
    public:
        int numberOfStableArrays(int zero, int one, int limit) {
            int mod = 1e9 + 7;
            vector<vector<vector<int>>> memo(zero + 1, vector<vector<int>>(one + 1, vector<int>(2, -1)));
    
            function<int(int, int, int)> dp = [&](int zero, int one, int lastBit) -> int {
                if (zero == 0) {
                    return (lastBit == 0 || one > limit) ? 0 : 1;
                } else if (one == 0) {
                    return (lastBit == 1 || zero > limit) ? 0 : 1;
                }
    
                if (memo[zero][one][lastBit] == -1) {
                    int res = 0;
                    if (lastBit == 0) {
                        res = (dp(zero - 1, one, 0) + dp(zero - 1, one, 1)) % mod;
                        if (zero > limit) {
                            res = (res - dp(zero - limit - 1, one, 1) + mod) % mod;
                        }
                    } else {
                        res = (dp(zero, one - 1, 0) + dp(zero, one - 1, 1)) % mod;
                        if (one > limit) {
                            res = (res - dp(zero, one - limit - 1, 0) + mod) % mod;
                        }
                    }
                    memo[zero][one][lastBit] = res % mod;
                }
                return memo[zero][one][lastBit];
            };
    
            return (dp(zero, one, 0) + dp(zero, one, 1)) % mod;
        }
    };
    

    ###Java

    class Solution {
        static final int MOD = 1000000007;
        int[][][] memo;
        int limit;
    
        public int numberOfStableArrays(int zero, int one, int limit) {
            this.memo = new int[zero + 1][one + 1][2];
            for (int i = 0; i <= zero; i++) {
                for (int j = 0; j <= one; j++) {
                    Arrays.fill(memo[i][j], -1);
                }
            }
            this.limit = limit;
            return (dp(zero, one, 0) + dp(zero, one, 1)) % MOD;
        }
    
        public int dp(int zero, int one, int lastBit) {
            if (zero == 0) {
                return (lastBit == 0 || one > limit) ? 0 : 1;
            } else if (one == 0) {
                return (lastBit == 1 || zero > limit) ? 0 : 1;
            }
    
            if (memo[zero][one][lastBit] == -1) {
                int res = 0;
                if (lastBit == 0) {
                    res = (dp(zero - 1, one, 0) + dp(zero - 1, one, 1))% MOD;
                    if (zero > limit) {
                        res = (res - dp(zero - limit - 1, one, 1) + MOD) % MOD;
                    }
                } else {
                    res = (dp(zero, one - 1, 0) + dp(zero, one - 1, 1)) % MOD;
                    if (one > limit) {
                        res = (res - dp(zero, one - limit - 1, 0) + MOD) % MOD;
                    }
                }
                memo[zero][one][lastBit] = res % MOD;
            }
            return memo[zero][one][lastBit];
        }
    }
    

    ###C#

    public class Solution {
        const int MOD = 1000000007;
        int[][][] memo;
        int limit;
    
        public int NumberOfStableArrays(int zero, int one, int limit) {
            this.memo = new int[zero + 1][][];
            for (int i = 0; i <= zero; i++) {
                memo[i] = new int[one + 1][];
                for (int j = 0; j <= one; j++) {
                    memo[i][j] = new int[2];
                    Array.Fill(memo[i][j], -1);
                }
            }
            this.limit = limit;
            return (DP(zero, one, 0) + DP(zero, one, 1)) % MOD;
        }
    
        public int DP(int zero, int one, int lastBit) {
            if (zero == 0) {
                return (lastBit == 0 || one > limit) ? 0 : 1;
            } else if (one == 0) {
                return (lastBit == 1 || zero > limit) ? 0 : 1;
            }
    
            if (memo[zero][one][lastBit] == -1) {
                int res = 0;
                if (lastBit == 0) {
                    res = (DP(zero - 1, one, 0) + DP(zero - 1, one, 1))% MOD;
                    if (zero > limit) {
                        res = (res - DP(zero - limit - 1, one, 1) + MOD) % MOD;
                    }
                } else {
                    res = (DP(zero, one - 1, 0) + DP(zero, one - 1, 1)) % MOD;
                    if (one > limit) {
                        res = (res - DP(zero, one - limit - 1, 0) + MOD) % MOD;
                    }
                }
                memo[zero][one][lastBit] = res % MOD;
            }
            return memo[zero][one][lastBit];
        }
    }
    

    ###C

    #define MOD 1000000007
    
    int ***createMemo(int zero, int one) {
        int ***memo = malloc((zero + 1) * sizeof(int **));
        for (int i = 0; i <= zero; ++i) {
            memo[i] = malloc((one + 1) * sizeof(int *));
            for (int j = 0; j <= one; ++j) {
                memo[i][j] = malloc(2 * sizeof(int));
                memo[i][j][0] = -1;
                memo[i][j][1] = -1;
            }
        }
        return memo;
    }
    
    void freeMemo(int zero, int one, int ***memo) {
        for (int i = 0; i <= zero; ++i) {
            for (int j = 0; j <= one; ++j) {
                free(memo[i][j]);
            }
            free(memo[i]);
        }
        free(memo);
    }
    
    int dp(int zero, int one, int lastBit, int limit, int ***memo) {
        if (zero == 0) {
            return (lastBit == 0 || one > limit) ? 0 : 1;
        } else if (one == 0) {
            return (lastBit == 1 || zero > limit) ? 0 : 1;
        }
        if (memo[zero][one][lastBit] == -1) {
            int res = 0;
            if (lastBit == 0) {
                res = (dp(zero - 1, one, 0, limit, memo) + dp(zero - 1, one, 1, limit, memo)) % MOD;
                if (zero > limit) {
                    res = (res - dp(zero - limit - 1, one, 1, limit, memo) + MOD) % MOD;
                }
            } else {
                res = (dp(zero, one - 1, 0, limit, memo) + dp(zero, one - 1, 1, limit, memo)) % MOD;
                if (one > limit) {
                    res = (res - dp(zero, one - limit - 1, 0, limit, memo) + MOD) % MOD;
                }
            }
            memo[zero][one][lastBit] = res % MOD;
        }
        return memo[zero][one][lastBit];
    }
    
    int numberOfStableArrays(int zero, int one, int limit) {
        int ***memo = createMemo(zero, one);
        int result = (dp(zero, one, 0, limit, memo) + dp(zero, one, 1, limit, memo)) % MOD;
        freeMemo(zero, one, memo);
        return result;
    }
    

    ###Go

    const MOD = 1000000007
    
    func numberOfStableArrays(zero int, one int, limit int) int {
        memo := make([][][]int, zero + 1)
    for i := range memo {
    memo[i] = make([][]int, one + 1)
    for j := range memo[i] {
    memo[i][j] = []int{-1, -1}
    }
    }
    
    var dp func(int, int, int) int
    dp = func(zero, one, lastBit int) int {
    if zero == 0 {
    if lastBit == 0 || one > limit {
    return 0
    } else {
    return 1
    }
    } else if one == 0 {
    if lastBit == 1 || zero > limit {
    return 0
    } else {
    return 1
    }
    }
    
    if memo[zero][one][lastBit] == -1 {
    res := 0
    if lastBit == 0 {
    res = (dp(zero-1, one, 0) + dp(zero - 1, one, 1)) % MOD
    if zero > limit {
    res = (res - dp(zero - limit - 1, one, 1) + MOD) % MOD
    }
    } else {
    res = (dp(zero, one - 1, 0) + dp(zero, one - 1, 1)) % MOD
    if one > limit {
    res = (res - dp(zero, one - limit - 1, 0) + MOD) % MOD
    }
    }
    memo[zero][one][lastBit] = res % MOD
    }
    return memo[zero][one][lastBit]
    }
    
    return (dp(zero, one, 0) + dp(zero, one, 1)) % MOD
    }
    

    ###JavaScript

    const MOD = 1000000007;
    
    var numberOfStableArrays = function(zero, one, limit) {
        const memo = Array.from({ length: zero + 1 }, () =>
            Array.from({ length: one + 1 }, () => [-1, -1])
        );
    
        function dp(zero, one, lastBit) {
            if (zero === 0) {
                return lastBit === 0 || one > limit ? 0 : 1;
            } else if (one === 0) {
                return lastBit === 1 || zero > limit ? 0 : 1;
            }
    
            if (memo[zero][one][lastBit] === -1) {
                let res = 0;
                if (lastBit === 0) {
                    res = (dp(zero - 1, one, 0) + dp(zero - 1, one, 1)) % MOD;
                    if (zero > limit) {
                        res = (res - dp(zero - limit - 1, one, 1) + MOD) % MOD;
                    }
                } else {
                    res = (dp(zero, one - 1, 0) + dp(zero, one - 1, 1)) % MOD;
                    if (one > limit) {
                        res = (res - dp(zero, one - limit - 1, 0) + MOD) % MOD;
                    }
                }
                memo[zero][one][lastBit] = res % MOD;
            }
            return memo[zero][one][lastBit];
        }
    
        return (dp(zero, one, 0) + dp(zero, one, 1)) % MOD;
    };
    

    ###TypeScript

    const MOD = 1000000007;
    
    function numberOfStableArrays(zero: number, one: number, limit: number): number {
        const memo: number[][][] = Array.from({ length: zero + 1 }, () =>
            Array.from({ length: one + 1 }, () => [-1, -1])
        );
    
        function dp(zero: number, one: number, lastBit: number): number {
            if (zero === 0) {
                return lastBit === 0 || one > limit ? 0 : 1;
            } else if (one === 0) {
                return lastBit === 1 || zero > limit ? 0 : 1;
            }
    
            if (memo[zero][one][lastBit] === -1) {
                let res = 0;
                if (lastBit === 0) {
                    res = (dp(zero - 1, one, 0) + dp(zero - 1, one, 1)) % MOD;
                    if (zero > limit) {
                        res = (res - dp(zero - limit - 1, one, 1) + MOD) % MOD;
                    }
                } else {
                    res = (dp(zero, one - 1, 0) + dp(zero, one - 1, 1)) % MOD;
                    if (one > limit) {
                        res = (res - dp(zero, one - limit - 1, 0) + MOD) % MOD;
                    }
                }
                memo[zero][one][lastBit] = res % MOD;
            }
            return memo[zero][one][lastBit];
        }
    
        return (dp(zero, one, 0) + dp(zero, one, 1)) % MOD;
    };
    

    ###Rust

    const MOD: i32 = 1000000007;
    
    impl Solution {
        pub fn number_of_stable_arrays(zero: i32, one: i32, limit: i32) -> i32 {
            let mut memo = vec![vec![vec![-1; 2]; (one + 1) as usize]; (zero + 1) as usize];
    
            fn dp(zero: usize, one: usize, last_bit: usize, limit: usize, memo: &mut Vec<Vec<Vec<i32>>>) -> i32 {
                if zero == 0 {
                    return if last_bit == 0 || one > limit { 0 } else { 1 };
                } else if one == 0 {
                    return if last_bit == 1 || zero > limit { 0 } else { 1 };
                }
    
                if memo[zero][one][last_bit] == -1 {
                    let mut res = 0;
                    if last_bit == 0 {
                        res = (dp(zero - 1, one, 0, limit, memo) + dp(zero - 1, one, 1, limit, memo)) % MOD;
                        if zero > limit {
                            res = (res - dp(zero - limit - 1, one, 1, limit, memo) + MOD) % MOD;
                        }
                    } else {
                        res = (dp(zero, one - 1, 0, limit, memo) + dp(zero, one - 1, 1, limit, memo)) % MOD;
                        if one > limit {
                            res = (res - dp(zero, one - limit - 1, 0, limit, memo) + MOD) % MOD;
                        }
                    }
                    memo[zero][one][last_bit] = res % MOD;
                }
                memo[zero][one][last_bit]
            }
    
            let zero = zero as usize;
            let one = one as usize;
            let limit = limit as usize;
            (dp(zero, one, 0, limit, &mut memo) + dp(zero, one, 1, limit, &mut memo)) % MOD
        }
    }
    

    复杂度分析

    • 时间复杂度:$O(\textit{zero}\times\textit{one})$,动态规划的状态一共有 $O(\textit{zero}\times\textit{one})$ 种,每个状态消耗 $O(1)$ 时间消耗。

    • 空间复杂度:$O(\textit{zero}\times\textit{one})$。

    方法二:动态规划

    思路

    方法一用的是记忆化搜索,状态的求解是自顶向下的。方法二中我们使用动态规划,从而自底向上来求出所有状态,并用数组保存结果。状态方程的关系和方法一一致。

    代码

    ###Python

    class Solution:
        def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:
            mod = 10 ** 9 + 7
    
            dp = [[[0, 0] for _ in range(one + 1)] for _ in range(zero + 1)]
            for i in range(zero+1):
                for j in range(one+1):
                    for lastBit in range(2):
                        if i == 0:
                            if lastBit == 0 or j > limit:
                                dp[i][j][lastBit] = 0
                            else:
                                dp[i][j][lastBit] = 1
                        elif j == 0:
                            if lastBit == 1 or i > limit:
                                dp[i][j][lastBit] = 0
                            else:
                                dp[i][j][lastBit] = 1
                        elif lastBit == 0:
                            dp[i][j][lastBit] = dp[i-1][j][0] + dp[i-1][j][1]
                            if i > limit:
                                dp[i][j][lastBit] -= dp[i-limit-1][j][1]
                        else:
                            dp[i][j][lastBit] = dp[i][j-1][0] + dp[i][j-1][1]
                            if j > limit:
                                dp[i][j][lastBit] -= dp[i][j-limit-1][0]
                        dp[i][j][lastBit] %= mod
            return (dp[-1][-1][0] + dp[-1][-1][1]) % mod
    

    ###C++

    class Solution {
    public:
        constexpr static int MOD = 1000000007;
        int numberOfStableArrays(int zero, int one, int limit) {
            vector<vector<vector<int>>> dp(zero + 1, vector<vector<int>>(one + 1, vector<int>(2)));
            for (int i = 0; i <= zero; i++) {
                for (int j = 0; j <= one; j++) {
                    for (int lastBit = 0; lastBit <= 1; lastBit++) {
                        if (i == 0) {
                            if (lastBit == 0 || j > limit) {
                                dp[i][j][lastBit] = 0;
                            } else {
                                dp[i][j][lastBit] = 1;
                            }
                        } else if (j == 0) {
                            if (lastBit == 1 || i > limit) {
                                dp[i][j][lastBit] = 0;
                            } else {
                                dp[i][j][lastBit] = 1;
                            }
                        } else if (lastBit == 0) {
                            dp[i][j][lastBit] = dp[i - 1][j][0] + dp[i - 1][j][1];
                            if (i > limit) {
                                dp[i][j][lastBit] -= dp[i - limit - 1][j][1];
                            }
                        } else {
                            dp[i][j][lastBit] = dp[i][j - 1][0] + dp[i][j -1 ][1];
                            if (j > limit) {
                                dp[i][j][lastBit] -= dp[i][j - limit - 1][0];
                            }
                        }
                        dp[i][j][lastBit] %= MOD;
                        if (dp[i][j][lastBit] < 0) {
                            dp[i][j][lastBit] += MOD;
                        }
                    }
                }
            }
    
            return (dp[zero][one][0] + dp[zero][one][1]) % MOD;
        }
    };
    

    ###Java

    class Solution {
        public int numberOfStableArrays(int zero, int one, int limit) {
            final int MOD = 1000000007;
            int[][][] dp = new int[zero + 1][one + 1][2];
            for (int i = 0; i <= zero; i++) {
                for (int j = 0; j <= one; j++) {
                    for (int lastBit = 0; lastBit <= 1; lastBit++) {
                        if (i == 0) {
                            if (lastBit == 0 || j > limit) {
                                dp[i][j][lastBit] = 0;
                            } else {
                                dp[i][j][lastBit] = 1;
                            }
                        } else if (j == 0) {
                            if (lastBit == 1 || i > limit) {
                                dp[i][j][lastBit] = 0;
                            } else {
                                dp[i][j][lastBit] = 1;
                            }
                        } else if (lastBit == 0) {
                            dp[i][j][lastBit] = dp[i - 1][j][0] + dp[i - 1][j][1];
                            if (i > limit) {
                                dp[i][j][lastBit] -= dp[i - limit - 1][j][1];
                            }
                        } else {
                            dp[i][j][lastBit] = dp[i][j - 1][0] + dp[i][j -1 ][1];
                            if (j > limit) {
                                dp[i][j][lastBit] -= dp[i][j - limit - 1][0];
                            }
                        }
                        dp[i][j][lastBit] %= MOD;
                        if (dp[i][j][lastBit] < 0) {
                            dp[i][j][lastBit] += MOD;
                        }
                    }
                }
            }
            return (dp[zero][one][0] + dp[zero][one][1]) % MOD;
        }
    }
    

    ###C#

    public class Solution {
        public int NumberOfStableArrays(int zero, int one, int limit) {
            const int MOD = 1000000007;
            int[][][] dp = new int[zero + 1][][];
            for (int i = 0; i <= zero; i++) {
                dp[i] = new int[one + 1][];
                for (int j = 0; j <= one; j++) {
                    dp[i][j] = new int[2];
                    for (int lastBit = 0; lastBit <= 1; lastBit++) {
                        if (i == 0) {
                            if (lastBit == 0 || j > limit) {
                                dp[i][j][lastBit] = 0;
                            } else {
                                dp[i][j][lastBit] = 1;
                            }
                        } else if (j == 0) {
                            if (lastBit == 1 || i > limit) {
                                dp[i][j][lastBit] = 0;
                            } else {
                                dp[i][j][lastBit] = 1;
                            }
                        } else if (lastBit == 0) {
                            dp[i][j][lastBit] = dp[i - 1][j][0] + dp[i - 1][j][1];
                            if (i > limit) {
                                dp[i][j][lastBit] -= dp[i - limit - 1][j][1];
                            }
                        } else {
                            dp[i][j][lastBit] = dp[i][j - 1][0] + dp[i][j -1 ][1];
                            if (j > limit) {
                                dp[i][j][lastBit] -= dp[i][j - limit - 1][0];
                            }
                        }
                        dp[i][j][lastBit] %= MOD;
                        if (dp[i][j][lastBit] < 0) {
                            dp[i][j][lastBit] += MOD;
                        }
                    }
                }
            }
            return (dp[zero][one][0] + dp[zero][one][1]) % MOD;
        }
    }
    

    ###Go

    const MOD = 1000000007
    
    func numberOfStableArrays(zero int, one int, limit int) int {
        dp := make([][][]int, zero + 1)
        for i := range dp {
            dp[i] = make([][]int, one + 1)
            for j := range dp[i] {
                dp[i][j] = make([]int, 2)
            }
        }
    
        for i := 0; i <= zero; i++ {
            for j := 0; j <= one; j++ {
                for lastBit := 0; lastBit <= 1; lastBit++ {
                    if i == 0 {
                        if lastBit == 0 || j > limit {
                            dp[i][j][lastBit] = 0
                        } else {
                            dp[i][j][lastBit] = 1
                        }
                    } else if j == 0 {
                        if lastBit == 1 || i > limit {
                            dp[i][j][lastBit] = 0
                        } else {
                            dp[i][j][lastBit] = 1
                        }
                    } else if lastBit == 0 {
                        dp[i][j][lastBit] = dp[i - 1][j][0] + dp[i - 1][j][1]
                        if i > limit {
                            dp[i][j][lastBit] -= dp[i - limit - 1][j][1]
                        }
                    } else {
                        dp[i][j][lastBit] = dp[i][j - 1][0] + dp[i][j - 1][1]
                        if j > limit {
                            dp[i][j][lastBit] -= dp[i][j - limit - 1][0]
                        }
                    }
                    dp[i][j][lastBit] %= MOD
                    if dp[i][j][lastBit] < 0 {
                        dp[i][j][lastBit] += MOD
                    }
                }
            }
        }
    
        return (dp[zero][one][0] + dp[zero][one][1]) % MOD
    }
    

    ###C

    #define MOD 1000000007
    
    int numberOfStableArrays(int zero, int one, int limit) {
        int dp[zero + 1][one + 1][2];
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i <= zero; i++) {
            for (int j = 0; j <= one; j++) {
                for (int lastBit = 0; lastBit <= 1; lastBit++) {
                    if (i == 0) {
                        if (lastBit == 0 || j > limit) {
                            dp[i][j][lastBit] = 0;
                        } else {
                            dp[i][j][lastBit] = 1;
                        }
                    } else if (j == 0) {
                        if (lastBit == 1 || i > limit) {
                            dp[i][j][lastBit] = 0;
                        } else {
                            dp[i][j][lastBit] = 1;
                        }
                    } else if (lastBit == 0) {
                        dp[i][j][lastBit] = dp[i - 1][j][0] + dp[i - 1][j][1];
                        if (i > limit) {
                            dp[i][j][lastBit] -= dp[i - limit - 1][j][1];
                        }
                    } else {
                        dp[i][j][lastBit] = dp[i][j - 1][0] + dp[i][j - 1][1];
                        if (j > limit) {
                            dp[i][j][lastBit] -= dp[i][j - limit - 1][0];
                        }
                    }
                    dp[i][j][lastBit] %= MOD;
                    if (dp[i][j][lastBit] < 0) {
                        dp[i][j][lastBit] += MOD;
                    }
                }
            }
        }
    
        return (dp[zero][one][0] + dp[zero][one][1]) % MOD;
    }
    

    ###JavaScript

    const MOD = 1000000007;
    
    var numberOfStableArrays = function(zero, one, limit) {
        let dp = Array.from({ length: zero + 1 }, () =>
            Array.from({ length: one + 1 }, () => [0, 0])
        );
    
        for (let i = 0; i <= zero; i++) {
            for (let j = 0; j <= one; j++) {
                for (let lastBit = 0; lastBit <= 1; lastBit++) {
                    if (i === 0) {
                        if (lastBit === 0 || j > limit) {
                            dp[i][j][lastBit] = 0;
                        } else {
                            dp[i][j][lastBit] = 1;
                        }
                    } else if (j === 0) {
                        if (lastBit === 1 || i > limit) {
                            dp[i][j][lastBit] = 0;
                        } else {
                            dp[i][j][lastBit] = 1;
                        }
                    } else if (lastBit === 0) {
                        dp[i][j][lastBit] = dp[i - 1][j][0] + dp[i - 1][j][1];
                        if (i > limit) {
                            dp[i][j][lastBit] -= dp[i - limit - 1][j][1];
                        }
                    } else {
                        dp[i][j][lastBit] = dp[i][j - 1][0] + dp[i][j - 1][1];
                        if (j > limit) {
                            dp[i][j][lastBit] -= dp[i][j - limit - 1][0];
                        }
                    }
                    dp[i][j][lastBit] %= MOD;
                    if (dp[i][j][lastBit] < 0) {
                        dp[i][j][lastBit] += MOD;
                    }
                }
            }
        }
    
        return (dp[zero][one][0] + dp[zero][one][1]) % MOD;
    };
    

    ###TypeScript

    const MOD = 1000000007;
    
    function numberOfStableArrays(zero: number, one: number, limit: number): number {
        let dp: number[][][] = Array.from({ length: zero + 1 }, () =>
            Array.from({ length: one + 1 }, () => [0, 0])
        );
    
        for (let i = 0; i <= zero; i++) {
            for (let j = 0; j <= one; j++) {
                for (let lastBit = 0; lastBit <= 1; lastBit++) {
                    if (i === 0) {
                        if (lastBit === 0 || j > limit) {
                            dp[i][j][lastBit] = 0;
                        } else {
                            dp[i][j][lastBit] = 1;
                        }
                    } else if (j === 0) {
                        if (lastBit === 1 || i > limit) {
                            dp[i][j][lastBit] = 0;
                        } else {
                            dp[i][j][lastBit] = 1;
                        }
                    } else if (lastBit === 0) {
                        dp[i][j][lastBit] = dp[i - 1][j][0] + dp[i - 1][j][1];
                        if (i > limit) {
                            dp[i][j][lastBit] -= dp[i - limit - 1][j][1];
                        }
                    } else {
                        dp[i][j][lastBit] = dp[i][j - 1][0] + dp[i][j - 1][1];
                        if (j > limit) {
                            dp[i][j][lastBit] -= dp[i][j - limit - 1][0];
                        }
                    }
                    dp[i][j][lastBit] %= MOD;
                    if (dp[i][j][lastBit] < 0) {
                        dp[i][j][lastBit] += MOD;
                    }
                }
            }
        }
    
        return (dp[zero][one][0] + dp[zero][one][1]) % MOD;
    };
    

    ###Rust

    const MOD: i32 = 1000000007;
    
    impl Solution {
        pub fn number_of_stable_arrays(zero: i32, one: i32, limit: i32) -> i32 {
            let mut dp = vec![vec![vec![0; 2]; one as usize + 1]; zero as usize + 1];
    
            for i in 0..=zero as usize {
                for j in 0..=one as usize {
                    for last_bit in 0..=1 {
                        if i == 0 {
                            if last_bit == 0 || j > limit as usize {
                                dp[i][j][last_bit] = 0;
                            } else {
                                dp[i][j][last_bit] = 1;
                            }
                        } else if j == 0 {
                            if last_bit == 1 || i > limit as usize {
                                dp[i][j][last_bit] = 0;
                            } else {
                                dp[i][j][last_bit] = 1;
                            }
                        } else if last_bit == 0 {
                            dp[i][j][last_bit] = dp[i - 1][j][0] + dp[i - 1][j][1];
                            if i > limit as usize {
                                dp[i][j][last_bit] -= dp[i - (limit as usize) - 1][j][1];
                            }
                        } else {
                            dp[i][j][last_bit] = dp[i][j - 1][0] + dp[i][j - 1][1];
                            if j > limit as usize {
                                dp[i][j][last_bit] -= dp[i][j - (limit as usize) - 1][0];
                            }
                        }
                        dp[i][j][last_bit] %= MOD;
                        if dp[i][j][last_bit] < 0 {
                            dp[i][j][last_bit] += MOD;
                        }
                    }
                }
            }
    
            return (dp[zero as usize][one as usize][0] + dp[zero as usize][one as usize][1]) % MOD;
        }
    }
    

    复杂度分析

    • 时间复杂度:$O(\textit{zero}\times\textit{one})$,动态规划的状态一共有 $O(\textit{zero}\times\textit{one})$ 种,每个状态消耗 $O(1)$ 时间消耗。

    • 空间复杂度:$O(\textit{zero}\times\textit{one})$。

    从 DP 到组合数学(Python/Java/C++/Go)

    作者 endlesscheng
    2024年4月28日 09:25

    方法一:记忆化搜索

    前置知识动态规划入门:从记忆化搜索到递推,其中包含如何把记忆化搜索 1:1 翻译成递推的技巧。

    先解释 $\textit{limit}$,意思是数组中至多有连续 $\textit{limit}$ 个 $0$,且至多有连续 $\textit{limit}$ 个 $1$。

    看示例 3,$\textit{zero}=3,\ \textit{one}=3,\ \textit{limit}=2$。

    考虑稳定数组的最后一个位置填 $0$ 还是 $1$:

    • 填 $0$,问题变成剩下 $2$ 个 $0$ 和 $3$ 个 $1$ 怎么填。
    • 填 $1$,问题变成剩下 $3$ 个 $0$ 和 $2$ 个 $1$ 怎么填。
    • 这两个都是和原问题相似的子问题。

    看上去,定义 $\textit{dfs}(i,j)$ 表示用 $i$ 个 $0$ 和 $j$ 个 $1$ 构造稳定数组的方案数?但这样定义不方便计算 $\textit{limit}$ 带来的影响。

    比如 $\textit{limit}=3$,如果在以 $1000$ 结尾的稳定数组的后面,再添加一个 $0$,得到以 $10000$ 结尾的数组,这是不合法的。我们需要把这种不合法的情况减掉。

    为了减去不合法的情况,我们需要知道稳定数组的最后一个数是 $0$ 还是 $1$。

    改成定义 $\textit{dfs}(i,j,k)$ 表示用 $i$ 个 $0$ 和 $j$ 个 $1$ 构造长为 $i+j$ 的稳定数组的方案数,其中最后一个位置(第 $i+j$ 个位置)已经填入了 $k$,其中 $k$ 为 $0$ 或 $1$。

    以 $k=0$ 为例,考虑 $\textit{dfs}(i,j,0)$ 怎么算。现在最后一个位置(第 $i+j$ 个位置)已经填入了 $0$,消耗了一个 $0$,还剩下 $i-1$ 个 $0$。问题变成用 $i-1$ 个 $0$ 和 $j$ 个 $1$ 构造长为 $i+j-1$ 的稳定数组的方案数。对于这个子问题,枚举最后一个位置(第 $i+j-1$ 个位置)填入 $k=0$ 还是 $k=1$,对应的方案数为 $\textit{dfs}(i-1,j,0)$ 和 $\textit{dfs}(i-1,j,1)$。

    看上去,把这两种情况加起来,我们就得到了

    $$
    \textit{dfs}(i,j,0) = \textit{dfs}(i-1,j,0) + \textit{dfs}(i-1,j,1)
    $$

    但是,这会产生不合法的情况。

    以 $\textit{limit}=3$ 为例说明。$\textit{dfs}(i-1,j,0)$ 是一些以 $0$ 结尾的稳定数组(合法数组),讨论末尾 $0$ 的个数:

    • 末尾恰好有连续 $1$ 个 $0$,即 $10$。
    • 末尾恰好有连续 $2$ 个 $0$,即 $100$。
    • 末尾恰好有连续 $3$ 个 $0$,即 $1000$。由于末尾不能超过连续 $3$ 个 $0$,末尾是 $000$ 的稳定数组,倒数第 $4$ 个数一定是 $1$,也就是在 $\textit{dfs}(i-1,j,0)$ 中有 $\textit{dfs}(i-4,j,1)$ 个末尾是 $1000$ 的稳定数组。

    若要通过 $\textit{dfs}(i-1,j,0)$ 计算 $\textit{dfs}(i,j,0)$,相当于往这 $\textit{dfs}(i-1,j,0)$ 个稳定数组的末尾再加一个 $0$:

    • 末尾恰好有连续 $2$ 个 $0$,即 $100$,这是合法的。
    • 末尾恰好有连续 $3$ 个 $0$,即 $1000$,这是合法的。
    • 末尾恰好有连续 $4$ 个 $0$,即 $10000$,这是不合法的,要全部去掉!根据上面的分析,要减去 $\textit{dfs}(i-4,j,1)$。

    一般地,在 $\textit{dfs}(i-1,j,0)$ 个稳定数组的末尾添加一个 $0$,会得到 $\textit{dfs}(i-\textit{limit}-1,j,1)$ 个不合法的数组。从上文的状态转移方程中减掉 $\textit{dfs}(i-\textit{limit}-1,j,1)$,得

    $$
    \textit{dfs}(i,j,0) = \textit{dfs}(i-1,j,0) + \textit{dfs}(i-1,j,1) - \textit{dfs}(i-\textit{limit}-1,j,1)
    $$

    同理得

    $$
    \textit{dfs}(i,j,1) = \textit{dfs}(i,j-1,0) + \textit{dfs}(i,j-1,1) - \textit{dfs}(i,j-\textit{limit}-1,0)
    $$

    递归边界

    • 如果 $i<0$ 或者 $j<0$,返回 $0$。也可以在递归 $\textit{dfs}(i-\textit{limit}-1,j,1)$ 前判断 $i>\textit{limit}$,在递归 $\textit{dfs}(i,j-\textit{limit}-1,0)$ 前判断 $j>\textit{limit}$。下面代码在递归前判断。
    • 如果 $i=0$,那么当 $k=1$ 且 $j\le \textit{limit}$ 的情况下返回 $1$,否则返回 $0$;如果 $j=0$,那么当 $k=0$ 且 $i\le \textit{limit}$ 的情况下返回 $1$,否则返回 $0$。

    递归入口:$\textit{dfs}(\textit{zero},\textit{one},0)+\textit{dfs}(\textit{zero},\textit{one},1)$,即答案。

    请看 视频讲解 第四题,欢迎点赞关注~

    ###py

    class Solution:
        def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:
            MOD = 1_000_000_007
            @cache  # 缓存装饰器,避免重复计算 dfs 的结果(记忆化)
            def dfs(i: int, j: int, k: int) -> int:
                if i == 0:
                    return 1 if k == 1 and j <= limit else 0
                if j == 0:
                    return 1 if k == 0 and i <= limit else 0
                if k == 0:
                    return (dfs(i - 1, j, 0) + dfs(i - 1, j, 1) - (dfs(i - limit - 1, j, 1) if i > limit else 0)) % MOD
                else:  # else 可以去掉,这里仅仅是为了代码对齐
                    return (dfs(i, j - 1, 0) + dfs(i, j - 1, 1) - (dfs(i, j - limit - 1, 0) if j > limit else 0)) % MOD
            ans = (dfs(zero, one, 0) + dfs(zero, one, 1)) % MOD
            dfs.cache_clear()  # 防止爆内存
            return ans
    

    ###java

    class Solution {
        private static final int MOD = 1_000_000_007;
    
        public int numberOfStableArrays(int zero, int one, int limit) {
            int[][][] memo = new int[zero + 1][one + 1][2];
            for (int[][] m : memo) {
                for (int[] m2 : m) {
                    Arrays.fill(m2, -1); // -1 表示没有计算过
                }
            }
            return (dfs(zero, one, 0, limit, memo) + dfs(zero, one, 1, limit, memo)) % MOD;
        }
    
        private int dfs(int i, int j, int k, int limit, int[][][] memo) {
            if (i == 0) { // 递归边界
                return k == 1 && j <= limit ? 1 : 0;
            }
            if (j == 0) { // 递归边界
                return k == 0 && i <= limit ? 1 : 0;
            }
            if (memo[i][j][k] != -1) { // 之前计算过
                return memo[i][j][k];
            }
            if (k == 0) {
                // + MOD 保证答案非负
                memo[i][j][k] = (int) (((long) dfs(i - 1, j, 0, limit, memo) + dfs(i - 1, j, 1, limit, memo) +
                        (i > limit ? MOD - dfs(i - limit - 1, j, 1, limit, memo) : 0)) % MOD);
            } else {
                memo[i][j][k] = (int) (((long) dfs(i, j - 1, 0, limit, memo) + dfs(i, j - 1, 1, limit, memo) +
                        (j > limit ? MOD - dfs(i, j - limit - 1, 0, limit, memo) : 0)) % MOD);
            }
            return memo[i][j][k];
        }
    }
    

    ###cpp

    class Solution {
    public:
        int numberOfStableArrays(int zero, int one, int limit) {
            const int MOD = 1'000'000'007;
            vector memo(zero + 1, vector<array<int, 2>>(one + 1, {-1, -1})); // -1 表示没有计算过
    
            auto dfs = [&](this auto&& dfs, int i, int j, int k) -> int {
                if (i == 0) { // 递归边界
                    return k == 1 && j <= limit;
                }
                if (j == 0) { // 递归边界
                    return k == 0 && i <= limit;
                }
                int& res = memo[i][j][k]; // 注意这里是引用
                if (res != -1) { // 之前计算过
                    return res;
                }
                if (k == 0) {
                    // + MOD 保证答案非负
                    res = ((long long) dfs(i - 1, j, 0) + dfs(i - 1, j, 1) +
                           (i > limit ? MOD - dfs(i - limit - 1, j, 1) : 0)) % MOD;
                } else {
                    res = ((long long) dfs(i, j - 1, 0) + dfs(i, j - 1, 1) +
                           (j > limit ? MOD - dfs(i, j - limit - 1, 0) : 0)) % MOD;
                }
                return res;
            };
    
            return (dfs(zero, one, 0) + dfs(zero, one, 1)) % MOD;
        }
    };
    

    ###go

    func numberOfStableArrays(zero, one, limit int) int {
    const mod = 1_000_000_007
    memo := make([][][2]int, zero+1)
    for i := range memo {
    memo[i] = make([][2]int, one+1)
    for j := range memo[i] {
    memo[i][j] = [2]int{-1, -1}
    }
    }
    var dfs func(int, int, int) int
    dfs = func(i, j, k int) (res int) {
    if i == 0 { // 递归边界
    if k == 1 && j <= limit {
    return 1
    }
    return
    }
    if j == 0 { // 递归边界
    if k == 0 && i <= limit {
    return 1
    }
    return
    }
    p := &memo[i][j][k]
    if *p != -1 { // 之前计算过
    return *p
    }
    if k == 0 {
    // +mod 保证答案非负
    res = (dfs(i-1, j, 0) + dfs(i-1, j, 1)) % mod
    if i > limit {
    res = (res - dfs(i-limit-1, j, 1) + mod) % mod
    }
    } else {
    res = (dfs(i, j-1, 0) + dfs(i, j-1, 1)) % mod
    if j > limit {
    res = (res - dfs(i, j-limit-1, 0) + mod) % mod
    }
    }
    *p = res // 记忆化
    return
    }
    return (dfs(zero, one, 0) + dfs(zero, one, 1)) % mod
    }
    

    复杂度分析

    • 时间复杂度:$\mathcal{O}(\textit{zero}\cdot \textit{one})$。由于每个状态只会计算一次,动态规划的时间复杂度 $=$ 状态个数 $\times$ 单个状态的计算时间。本题状态个数等于 $\mathcal{O}(\textit{zero}\cdot \textit{one})$,单个状态的计算时间为 $\mathcal{O}(1)$,所以动态规划的时间复杂度为 $\mathcal{O}(\textit{zero}\cdot \textit{one})$。
    • 空间复杂度:$\mathcal{O}(\textit{zero}\cdot \textit{one})$。有多少个状态,$\textit{memo}$ 数组的大小就是多少。

    方法二:递推

    和 $\textit{dfs}(i,j,k)$ 一样,定义 $f[i][j][k]$ 表示用 $i$ 个 $0$ 和 $j$ 个 $1$ 构造稳定数组的方案数,其中第 $i+j$ 个位置要填 $k$,其中 $k$ 为 $0$ 或 $1$。

    状态转移方程:

    $$
    \begin{aligned}
    f[i][j][0] &= f[i-1][j][0] + f[i-1][j][1] - f[i-\textit{limit}-1][j][1] \
    f[i][j][1] &= f[i][j-1][0] + f[i][j-1][1] - f[i][j-\textit{limit}-1][0] \
    \end{aligned}
    $$

    如果 $i\le \textit{limit}$ 则 $f[i-\textit{limit}-1][j][1]$ 视作 $0$,如果 $j\le \textit{limit}$ 则 $f[i][j-\textit{limit}-1][0]$ 视作 $0$。

    初始值:$f[i][0][0] = f[0][j][1] = 1$,其中 $1\le i \le \min(\textit{limit}, \textit{zero}),\ 1\le j \le \min(\textit{limit}, \textit{one})$。翻译自递归边界。

    答案:$f[\textit{zero}][\textit{one}][0] + f[\textit{zero}][\textit{one}][1]$。翻译自递归入口。

    ###py

    class Solution:
        def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:
            MOD = 1_000_000_007
            f = [[[0, 0] for _ in range(one + 1)] for _ in range(zero + 1)]
            for i in range(1, min(limit, zero) + 1):
                f[i][0][0] = 1
            for j in range(1, min(limit, one) + 1):
                f[0][j][1] = 1
            for i in range(1, zero + 1):
                for j in range(1, one + 1):
                    f[i][j][0] = (f[i - 1][j][0] + f[i - 1][j][1] - (f[i - limit - 1][j][1] if i > limit else 0)) % MOD
                    f[i][j][1] = (f[i][j - 1][0] + f[i][j - 1][1] - (f[i][j - limit - 1][0] if j > limit else 0)) % MOD
            return sum(f[-1][-1]) % MOD
    

    ###java

    class Solution {
        public int numberOfStableArrays(int zero, int one, int limit) {
            final int MOD = 1_000_000_007;
            int[][][] f = new int[zero + 1][one + 1][2];
            for (int i = 1; i <= Math.min(limit, zero); i++) {
                f[i][0][0] = 1;
            }
            for (int j = 1; j <= Math.min(limit, one); j++) {
                f[0][j][1] = 1;
            }
            for (int i = 1; i <= zero; i++) {
                for (int j = 1; j <= one; j++) {
                    // + MOD 保证答案非负
                    f[i][j][0] = (int) (((long) f[i - 1][j][0] + f[i - 1][j][1] + (i > limit ? MOD - f[i - limit - 1][j][1] : 0)) % MOD);
                    f[i][j][1] = (int) (((long) f[i][j - 1][0] + f[i][j - 1][1] + (j > limit ? MOD - f[i][j - limit - 1][0] : 0)) % MOD);
                }
            }
            return (f[zero][one][0] + f[zero][one][1]) % MOD;
        }
    }
    

    ###cpp

    class Solution {
    public:
        int numberOfStableArrays(int zero, int one, int limit) {
            const int MOD = 1'000'000'007;
            vector<vector<array<int, 2>>> f(zero + 1, vector<array<int, 2>>(one + 1));
            for (int i = 1; i <= min(limit, zero); i++) {
                f[i][0][0] = 1;
            }
            for (int j = 1; j <= min(limit, one); j++) {
                f[0][j][1] = 1;
            }
            for (int i = 1; i <= zero; i++) {
                for (int j = 1; j <= one; j++) {
                    // + MOD 保证答案非负
                    f[i][j][0] = ((long long) f[i - 1][j][0] + f[i - 1][j][1] + (i > limit ? MOD - f[i - limit - 1][j][1] : 0)) % MOD;
                    f[i][j][1] = ((long long) f[i][j - 1][0] + f[i][j - 1][1] + (j > limit ? MOD - f[i][j - limit - 1][0] : 0)) % MOD;
                }
            }
            return (f[zero][one][0] + f[zero][one][1]) % MOD;
        }
    };
    

    ###go

    func numberOfStableArrays(zero, one, limit int) (ans int) {
    const mod = 1_000_000_007
    f := make([][][2]int, zero+1)
    for i := range f {
    f[i] = make([][2]int, one+1)
    }
    for i := 1; i <= min(limit, zero); i++ {
    f[i][0][0] = 1
    }
    for j := 1; j <= min(limit, one); j++ {
    f[0][j][1] = 1
    }
    for i := 1; i <= zero; i++ {
    for j := 1; j <= one; j++ {
    f[i][j][0] = (f[i-1][j][0] + f[i-1][j][1]) % mod
    if i > limit {
    // + mod 保证答案非负
    f[i][j][0] = (f[i][j][0] - f[i-limit-1][j][1] + mod) % mod
    }
    f[i][j][1] = (f[i][j-1][0] + f[i][j-1][1]) % mod
    if j > limit {
    f[i][j][1] = (f[i][j][1] - f[i][j-limit-1][0] + mod) % mod
    }
    }
    }
    return (f[zero][one][0] + f[zero][one][1]) % mod
    }
    

    复杂度分析

    • 时间复杂度:$\mathcal{O}(\textit{zero}\cdot \textit{one})$。
    • 空间复杂度:$\mathcal{O}(\textit{zero}\cdot \textit{one})$。

    方法三:容斥原理+乘法原理

    回顾一个经典的组合数学问题:

    • 把 $n$ 个无区别的小球,放入 $m$ 个有区别的盒子,不允许空盒,有多少种方案?

    这可以用隔板法解决,$n$ 个小球之间有 $n-1$ 个空隙,从中选择 $m-1$ 个空隙,插入 $m-1$ 个隔板,这样就把小球分成了 $m$ 组,并且每一组都是非空的,方案数就是 $n-1$ 选 $m-1$ 的组合数 $\dbinom {n-1} {m-1}$。

    • 只考虑 $0$,把 $0$ 分成 $i$ 组,方案数就是 $f_0[i] = \dbinom {\textit{zero}-1} {i-1}$;
    • 只考虑 $1$,把 $1$ 分成 $i$ 组,方案数就是 $f_1[i] = \dbinom {\textit{one}-1} {i-1}$。

    如何综合考虑 $0$ 和 $1$?要如何计算方案数?

    例如 $10110001$,相当于把 $0$ 分成了 $2$ 组,把 $1$ 分成了 $3$ 组。

    一般地,设 $1$ 分成了 $i$ 组,那么 $0$ 会分成多少组?有哪些情况?

    有如下四种情况:

    • $0$ 分成 $i-1$ 组,例如 $10110001$。注意第一个数和最后一个数一定是 $1$。
    • $0$ 分成 $i$ 组,且第一个数是 $0$,例如 $01010011$。注意最后一个数一定是 $1$。
    • $0$ 分成 $i$ 组,且第一个数是 $1$,例如 $10100110$。注意最后一个数一定是 $0$。
    • $0$ 分成 $i+1$ 组,例如 $01010110$。注意第一个数和最后一个数一定是 $0$。

    注意 $0$ 和 $1$ 内部的分组方案是互相独立的,例如

    $$
    \begin{aligned}
    &11010001\
    &10110001\
    &10100011
    \end{aligned}
    $$

    这些例子的 $0$ 的组数不变,$1$ 的组数不变,$0$ 的分组方式也不变(都是一个 $0$ 和三个 $0$),只有 $1$ 的分组方式在变。

    根据乘法原理,综合考虑 $0$ 和 $1$,把 $1$ 分成 $i$ 组总的方案数,等于上面说的四种情况(只考虑 $0$,把 $0$ 分成 $i-1,i,i+1$ 组)的方案数之和,乘以只考虑 $1$,把 $1$ 分成 $i$ 组的方案数,即

    $$
    (f_0[i-1] + 2\cdot f_0[i] + f_0[i+1])\cdot f_1[i]
    $$

    接下来,考虑 $\textit{limit}$ 带来的影响。推荐先看 2929. 给小朋友们分糖果 II 以及 我的题解

    根据容斥原理,对于 $f_0[i] = \dbinom {\textit{zero}-1} {i-1}$,我们需要减去「至少 $1$ 组有超过 $\textit{limit}$ 个 $0$」的方案数,再加上「至少 $2$ 组有超过 $\textit{limit}$ 个 $0$」的方案数,再减去「至少 $3$ 组有超过 $\textit{limit}$ 个 $0$」的方案数,……,直到「至少 $j$ 组有超过 $\textit{limit}$ 个 $0$」的方案数,$j$ 的值见下文。

    • 至少 $j$ 组有超过 $\textit{limit}$ 个 $0$,相当于先从 $i$ 组中选 $j$ 组,每组先放入 $\textit{limit}$ 个 $0$,然后再把剩下的 $\textit{zero} - j\cdot \textit{limit}$ 分成 $i$ 组(需要满足 $\textit{zero} - j\cdot \textit{limit} \ge i$),方案数为

    $$
    \dbinom {i} {j} \dbinom {\textit{zero} - j\cdot \textit{limit}-1} {i-1}
    $$

    所以

    $$
    f_0[i] = \dbinom {\textit{zero}-1} {i-1} + \sum_{j} (-1)^j \dbinom {i} {j} \dbinom {\textit{zero} - j\cdot \textit{limit}-1} {i-1}
    $$

    其中 $j\ge 1$ 且需要满足 $\textit{zero} - j\cdot \textit{limit} \ge i$,即

    $$
    1\le j\le \left\lfloor\dfrac{zero - i}{\textit{limit}}\right\rfloor
    $$

    同理有

    $$
    f_1[i] = \dbinom {\textit{one}-1} {i-1} + \sum_{j} (-1)^j \dbinom {i} {j} \dbinom {\textit{one} - j\cdot \textit{limit}-1} {i-1}
    $$

    其中

    $$
    1\le j\le \left\lfloor\dfrac{one - i}{\textit{limit}}\right\rfloor
    $$

    最终答案为

    $$
    \sum_{i} (f_0[i-1] + 2\cdot f_0[i] + f_0[i+1])\cdot f_1[i]
    $$

    其中:

    1. $i\le \textit{one}$。因为 $1$ 最多分成 $\textit{one}$ 组。
    2. $i-1\le \textit{zero}$。因为 $0$ 最多分成 $\textit{zero}$ 组,当 $i-1 > \textit{zero}$ 时,上式中的 $f_0[i-1] = f_0[i] = f_0[i+1] = 0$,无需累加。
    3. $i\cdot \textit{limit}\ge \textit{one}$,即 $i\ge\left\lceil\dfrac{\textit{one}}{\textit{limit}}\right\rceil$。因为每组至多 $\textit{limit}$ 个 $1$,分成 $i$ 组,至多 $i\cdot \textit{limit}$ 个 $1$,这个数必须 $\ge \textit{one}$,不然剩下的 $1$ 放到哪一组都会导致组内 $1$ 的个数超过 $\textit{limit}$。

    整理得

    $$
    \left\lceil\dfrac{\textit{one}}{\textit{limit}}\right\rceil \le i\le \min(\textit{one},\textit{zero}+1)
    $$

    代码实现时:

    1. 上取整 $\left\lceil\dfrac{a}{b}\right\rceil$ 转换成下取整 $\left\lfloor\dfrac{a-1}{b}\right\rfloor+1$。
    2. $(-1)^j$ 可以用 $1-j\bmod 2\cdot 2$ 表示,因为当 $j$ 是偶数时,该式为 $1$;当 $j$ 是奇数时,该式为 $-1$,符合 $(-1)^j$。
    3. 预处理阶乘及其逆元,利用公式 $\dbinom {n} {m} = \dfrac{n!}{m!(n-m)!}$ 计算组合数。

    关于取模的知识点,见 模运算的世界:当加减乘除遇上取模

    ###py

    MOD = 1_000_000_007
    MX = 1001
    
    fac = [0] * MX  # f[i] = i!
    fac[0] = 1
    for i in range(1, MX):
        fac[i] = fac[i - 1] * i % MOD
    
    inv_f = [0] * MX  # inv_f[i] = i!^-1
    inv_f[-1] = pow(fac[-1], -1, MOD)
    for i in range(MX - 1, 0, -1):
        inv_f[i - 1] = inv_f[i] * i % MOD
    
    def comb(n: int, m: int) -> int:
        return fac[n] * inv_f[m] * inv_f[n - m] % MOD
    
    class Solution:
        def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:
            if zero > one:
                zero, one = one, zero  # 保证空间复杂度为 O(min(zero, one))
            f0 = [0] * (zero + 3)
            for i in range((zero - 1) // limit + 1, zero + 1):
                f0[i] = comb(zero - 1, i - 1)
                for j in range(1, (zero - i) // limit + 1):
                    f0[i] = (f0[i] + (-1 if j % 2 else 1) * comb(i, j) * comb(zero - j * limit - 1, i - 1)) % MOD
    
            ans = 0
            for i in range((one - 1) // limit + 1, min(one, zero + 1) + 1):
                f1 = comb(one - 1, i - 1)
                for j in range(1, (one - i) // limit + 1):
                    f1 = (f1 + (-1 if j % 2 else 1) * comb(i, j) * comb(one - j * limit - 1, i - 1)) % MOD
                ans = (ans + (f0[i - 1] + f0[i] * 2 + f0[i + 1]) * f1) % MOD
            return ans
    

    ###java

    class Solution {
        private static final int MOD = 1_000_000_007;
        private static final int MX = 1001;
    
        private static final long[] F = new long[MX]; // f[i] = i!
        private static final long[] INV_F = new long[MX]; // inv_f[i] = i!^-1
    
        static {
            F[0] = 1;
            for (int i = 1; i < MX; i++) {
                F[i] = F[i - 1] * i % MOD;
            }
    
            INV_F[MX - 1] = pow(F[MX - 1], MOD - 2);
            for (int i = MX - 1; i > 0; i--) {
                INV_F[i - 1] = INV_F[i] * i % MOD;
            }
        }
    
        public int numberOfStableArrays(int zero, int one, int limit) {
            if (zero > one) {
                // swap,保证空间复杂度为 O(min(zero, one))
                int t = zero;
                zero = one;
                one = t;
            }
            long[] f0 = new long[zero + 3];
            for (int i = (zero - 1) / limit + 1; i <= zero; i++) {
                f0[i] = comb(zero - 1, i - 1);
                for (int j = 1; j <= (zero - i) / limit; j++) {
                    f0[i] = (f0[i] + (1 - j % 2 * 2) * comb(i, j) * comb(zero - j * limit - 1, i - 1)) % MOD;
                }
            }
    
            long ans = 0;
            for (int i = (one - 1) / limit + 1; i <= Math.min(one, zero + 1); i++) {
                long f1 = comb(one - 1, i - 1);
                for (int j = 1; j <= (one - i) / limit; j++) {
                    f1 = (f1 + (1 - j % 2 * 2) * comb(i, j) * comb(one - j * limit - 1, i - 1)) % MOD;
                }
                ans = (ans + (f0[i - 1] + f0[i] * 2 + f0[i + 1]) * f1) % MOD;
            }
            return (int) ((ans + MOD) % MOD); // 保证结果非负
        }
    
        private long comb(int n, int m) {
            return F[n] * INV_F[m] % MOD * INV_F[n - m] % MOD;
        }
    
        private static long pow(long x, int n) {
            long res = 1;
            for (; n > 0; n /= 2) {
                if (n % 2 > 0) {
                    res = res * x % MOD;
                }
                x = x * x % MOD;
            }
            return res;
        }
    }
    

    ###cpp

    const int MOD = 1'000'000'007;
    const int MX = 1001;
    
    long long F[MX]; // F[i] = i!
    long long INV_F[MX]; // INV_F[i] = i!^-1
    
    long long pow(long long x, int n) {
        long long res = 1;
        for (; n; n /= 2) {
            if (n % 2) {
                res = res * x % MOD;
            }
            x = x * x % MOD;
        }
        return res;
    }
    
    auto init = [] {
        F[0] = 1;
        for (int i = 1; i < MX; i++) {
            F[i] = F[i - 1] * i % MOD;
        }
    
        INV_F[MX - 1] = pow(F[MX - 1], MOD - 2);
        for (int i = MX - 1; i; i--) {
            INV_F[i - 1] = INV_F[i] * i % MOD;
        }
        return 0;
    }();
    
    long long comb(int n, int m) {
        return F[n] * INV_F[m] % MOD * INV_F[n - m] % MOD;
    }
    
    class Solution {
    public:
        int numberOfStableArrays(int zero, int one, int limit) {
            if (zero > one) {
                swap(zero, one); // 保证空间复杂度为 O(min(zero, one))
            }
            vector<long long> f0(zero + 3);
            for (int i = (zero - 1) / limit + 1; i <= zero; i++) {
                f0[i] = comb(zero - 1, i - 1);
                for (int j = 1; j <= (zero - i) / limit; j++) {
                    f0[i] = (f0[i] + (1 - j % 2 * 2) * comb(i, j) * comb(zero - j * limit - 1, i - 1)) % MOD;
                }
            }
    
            long long ans = 0;
            for (int i = (one - 1) / limit + 1; i <= min(one, zero + 1); i++) {
                long long f1 = comb(one - 1, i - 1);
                for (int j = 1; j <= (one - i) / limit; j++) {
                    f1 = (f1 + (1 - j % 2 * 2) * comb(i, j) * comb(one - j * limit - 1, i - 1)) % MOD;
                }
                ans = (ans + (f0[i - 1] + f0[i] * 2 + f0[i + 1]) * f1) % MOD;
            }
            return (ans + MOD) % MOD; // 保证结果非负
        }
    };
    

    ###go

    const mod = 1_000_000_007
    const mx = 1001
    
    var f [mx]int    // f[i] = i!
    var invF [mx]int // invF[i] = i!^-1
    
    func init() {
    f[0] = 1
    for i := 1; i < mx; i++ {
    f[i] = f[i-1] * i % mod
    }
    
    invF[mx-1] = pow(f[mx-1], mod-2)
    for i := mx - 1; i > 0; i-- {
    invF[i-1] = invF[i] * i % mod
    }
    }
    
    func comb(n, m int) int {
    return f[n] * invF[m] % mod * invF[n-m] % mod
    }
    
    func numberOfStableArrays(zero, one, limit int) (ans int) {
    if zero > one {
    zero, one = one, zero // 保证空间复杂度为 O(min(zero, one))
    }
    f0 := make([]int, zero+3)
    for i := (zero-1)/limit + 1; i <= zero; i++ {
    f0[i] = comb(zero-1, i-1)
    for j := 1; j <= (zero-i)/limit; j++ {
    f0[i] = (f0[i] + (1-j%2*2)*comb(i, j)*comb(zero-j*limit-1, i-1)) % mod
    }
    }
    
    for i := (one-1)/limit + 1; i <= min(one, zero+1); i++ {
    f1 := comb(one-1, i-1)
    for j := 1; j <= (one-i)/limit; j++ {
    f1 = (f1 + (1-j%2*2)*comb(i, j)*comb(one-j*limit-1, i-1)) % mod
    }
    ans = (ans + (f0[i-1]+f0[i]*2+f0[i+1])*f1) % mod
    }
    return (ans + mod) % mod // 保证结果非负
    }
    
    func pow(x, n int) int {
    res := 1
    for ; n > 0; n /= 2 {
    if n%2 > 0 {
    res = res * x % mod
    }
    x = x * x % mod
    }
    return res
    }
    

    复杂度分析

    • 时间复杂度:$\mathcal{O}\left(\dfrac{\textit{zero}\cdot\textit{one}}{\textit{limit}}\right)$。忽略预处理的时间和空间。
    • 空间复杂度:$\mathcal{O}(\min(\textit{zero},\textit{one}))$。

    分类题单

    如何科学刷题?

    1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
    2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
    3. 单调栈(基础/矩形面积/贡献法/最小字典序)
    4. 网格图(DFS/BFS/综合应用)
    5. 位运算(基础/性质/拆位/试填/恒等式/思维)
    6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
    7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
    8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
    9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
    10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
    11. 链表、二叉树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA/一般树)
    12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

    我的题解精选(已分类)

    欢迎关注 B站@灵茶山艾府

    昨天以前LeetCode 每日一题题解

    每日一题-找出所有稳定的二进制数组 I🟡

    2026年3月9日 00:00

    给你 3 个正整数 zero ,one 和 limit 。

    一个 二进制数组 arr 如果满足以下条件,那么我们称它是 稳定的

    • 0 在 arr 中出现次数 恰好 为 zero 。
    • 1 在 arr 中出现次数 恰好 为 one 。
    • arr 中每个长度超过 limit 的 子数组同时 包含 0 和 1 。

    请你返回 稳定 二进制数组的 数目。

    由于答案可能很大,将它对 109 + 7 取余 后返回。

     

    示例 1:

    输入:zero = 1, one = 1, limit = 2

    输出:2

    解释:

    两个稳定的二进制数组为 [1,0] 和 [0,1] ,两个数组都有一个 0 和一个 1 ,且没有子数组长度大于 2 。

    示例 2:

    输入:zero = 1, one = 2, limit = 1

    输出:1

    解释:

    唯一稳定的二进制数组是 [1,0,1] 。

    二进制数组 [1,1,0] 和 [0,1,1] 都有长度为 2 且元素全都相同的子数组,所以它们不稳定。

    示例 3:

    输入:zero = 3, one = 3, limit = 2

    输出:14

    解释:

    所有稳定的二进制数组包括 [0,0,1,0,1,1] ,[0,0,1,1,0,1] ,[0,1,0,0,1,1] ,[0,1,0,1,0,1] ,[0,1,0,1,1,0] ,[0,1,1,0,0,1] ,[0,1,1,0,1,0] ,[1,0,0,1,0,1] ,[1,0,0,1,1,0] ,[1,0,1,0,0,1] ,[1,0,1,0,1,0] ,[1,0,1,1,0,0] ,[1,1,0,0,1,0] 和 [1,1,0,1,0,0] 。

     

    提示:

    • 1 <= zero, one, limit <= 200

    找出所有稳定的二进制数组 I

    2024年8月1日 10:03

    方法一:动态规划

    题目要求二进制数组 $\textit{arr}$ 中每个长度超过 $\textit{limit}$ 的子数组同时包含 $0$ 和 $1$,这个条件等价于二进制数组 $\textit{arr}$ 中每个长度等于 $\textit{limit} + 1$ 的子数组都同时包含 $0$ 和 $1$(读者可以思考一下证明过程)。

    按照题目要求,我们需要将 $\textit{zero}$ 个 $0$ 和 $\textit{one}$ 个 $1$ 依次填入二进制数组 $\textit{arr}$,使用 $\textit{dp}_0[i][j]$ 表示已经填入 $i$ 个 $0$ 和 $\textit{j}$ 个 $1$,并且最后填入的数字为 $0$ 的可行方案数目,$\textit{dp}_1[i][j]$ 表示已经填入 $i$ 个 $0$ 和 $\textit{j}$ 个 $1$,并且最后填入的数字为 $1$ 的可行方案数目。对于 $\textit{dp}_0[i][j]$,我们分析一下它的转换方程:

    • 当 $j = 0$ 且 $i \in [0, \min(\textit{zero}, \textit{limit})]$ 时:我们可以不断地填入 $0$,所以 $\textit{dp}_0[i][j] = 1$。

    • 当 $i = 0$,或者 $j = 0$ 且 $i \notin [0, \min(\textit{zero}, \textit{limit})]$ 时:我们没法构造可行的方案,所以 $\textit{dp}_0[i][j] = 0$。

    • 当 $i > 0$ 且 $j > 0$ 时:$\textit{dp}_0[i][j]$ 可以分别由 $\textit{dp}_0[i - 1][j]$ 和 $\textit{dp}_1[i - 1][j]$ 转移而来,分别考虑两种情况:

      • 对于 $\textit{dp}_1[i - 1][j]$:显然可以通过在 $\textit{dp}_1[i - 1][j]$ 对应的所有填入方案后再填入一个 $0$ 得到对应的可行方案。

      • 对于 $\textit{dp}_0[i - 1][j]$:当 $i \le \textit{limit}$ 时,显然可以通过在 $\textit{dp}_1[i - 1][j]$ 对应的所有填入方案后再填入一个 $0$ 得到对应的可行方案;当 $i \gt \textit{limit}$ 时,我们需要去除一些不可行的方案数。因为 $\textit{dp}_0[i - 1][j]$ 对应的所有填入方案都是可行的,而只有一种情况会在额外填入一个 $0$ 时,变成不可行,即先前已经连续填入 $\textit{limit}$ 个 $0$,对应的方案数为 $\textit{dp}_1[i - \textit{limit} - 1][j]$。

    根据以上分析,我们有 $\textit{dp}_0[i][j]$ 的转移方程:

    $$
    \textit{dp}_0[i][j] = \begin{cases}
    1, & i \in [0, \min(\textit{zero}, \textit{limit})], j = 0 \
    \textit{dp}_1[i - 1][j] + \textit{dp}_0[i - 1][j] - \textit{dp}_1[i - \textit{limit} - 1][j], & i > limit, j > 0 \
    \textit{dp}_1[i - 1][j] + \textit{dp}_0[i - 1][j], & i \in [0, limit], j > 0 \
    0, & otherwise
    \end{cases}
    $$

    同理,我们也可以获得 $\textit{dp}_1[i][j]$ 的转移方程:

    $$
    \textit{dp}_1[i][j] = \begin{cases}
    1, & i = 0, j \in [0, \min(\textit{one}, \textit{limit})] \
    \textit{dp}_0[i][j - 1] + \textit{dp}_1[i][j - 1] - \textit{dp}_0[i][j - \textit{limit} - 1], & i > 0, j > limit \
    \textit{dp}_0[i][j - 1] + \textit{dp}_1[i][j - 1], & i > 0, j \in [0, limit] \
    0, & otherwise
    \end{cases}
    $$

    最后,稳定二进制数组的数目等于 $\textit{dp}_0[\textit{zero}][\textit{one}] + \textit{dp}_1[\textit{zero}][\textit{one}]$。

    ###C++

    class Solution {
    public:
        int numberOfStableArrays(int zero, int one, int limit) {
            vector<vector<vector<long long>>> dp(zero + 1, vector<vector<long long>>(one + 1, vector<long long>(2)));
            long long mod = 1e9 + 7;
            for (int i = 0; i <= min(zero, limit); i++) {
                dp[i][0][0] = 1;
            }
            for (int j = 0; j <= min(one, limit); j++) {
                dp[0][j][1] = 1;
            }
            for (int i = 1; i <= zero; i++) {
                for (int j = 1; j <= one; j++) {
                    if (i > limit) {
                        dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
                    } else {
                        dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                    }
                    dp[i][j][0] = (dp[i][j][0] % mod + mod) % mod;
                    if (j > limit) {
                        dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
                    } else {
                        dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                    }
                    dp[i][j][1] = (dp[i][j][1] % mod + mod) % mod;
                }
            }
            return (dp[zero][one][0] + dp[zero][one][1]) % mod;
        }
    };
    

    ###Java

    class Solution {
        public int numberOfStableArrays(int zero, int one, int limit) {
            final long MOD = 1000000007;
            long[][][] dp = new long[zero + 1][one + 1][2];
            for (int i = 0; i <= Math.min(zero, limit); i++) {
                dp[i][0][0] = 1;
            }
            for (int j = 0; j <= Math.min(one, limit); j++) {
                dp[0][j][1] = 1;
            }
            for (int i = 1; i <= zero; i++) {
                for (int j = 1; j <= one; j++) {
                    if (i > limit) {
                        dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
                    } else {
                        dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                    }
                    dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
                    if (j > limit) {
                        dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
                    } else {
                        dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                    }
                    dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
                }
            }
            return (int) ((dp[zero][one][0] + dp[zero][one][1]) % MOD);
        }
    }
    

    ###C#

    public class Solution {
        public int NumberOfStableArrays(int zero, int one, int limit) {
            const long MOD = 1000000007;
            long[][][] dp = new long[zero + 1][][];
            for (int i = 0; i <= zero; i++) {
                dp[i] = new long[one + 1][];
                for (int j = 0; j <= one; j++) {
                    dp[i][j] = new long[2];
                }
            }
            for (int i = 0; i <= Math.Min(zero, limit); i++) {
                dp[i][0][0] = 1;
            }
            for (int j = 0; j <= Math.Min(one, limit); j++) {
                dp[0][j][1] = 1;
            }
            for (int i = 1; i <= zero; i++) {
                for (int j = 1; j <= one; j++) {
                    if (i > limit) {
                        dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
                    } else {
                        dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                    }
                    dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
                    if (j > limit) {
                        dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
                    } else {
                        dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                    }
                    dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
                }
            }
            return (int) ((dp[zero][one][0] + dp[zero][one][1]) % MOD);
        }
    }
    

    ###Go

    func numberOfStableArrays(zero int, one int, limit int) int {
        dp := make([][][2]int, zero + 1)
        mod := int(1e9 + 7)
        for i := 0; i <= zero; i++ {
            dp[i] = make([][2]int, one + 1)
        }
        for i := 0; i <= min(zero, limit); i++ {
            dp[i][0][0] = 1
        }
        for j := 0; j <= min(one, limit); j++ {
            dp[0][j][1] = 1
        }
        for i := 1; i <= zero; i++ {
            for j := 1; j <= one; j++ {
                if i > limit {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1]
                } else {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1]
                }
                dp[i][j][0] = (dp[i][j][0] % mod + mod) % mod
                if j > limit {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0]
                } else {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0]
                }
                dp[i][j][1] = (dp[i][j][1] % mod + mod) % mod
            }
        }
        return (dp[zero][one][0] + dp[zero][one][1]) % mod
    }
    

    ###Python

    class Solution:
        def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:
            dp = [[[0, 0] for _ in range(one + 1)] for _ in range(zero + 1)]
            mod = int(1e9 + 7)
            for i in range(min(zero, limit) + 1):
                dp[i][0][0] = 1
            for j in range(min(one, limit) + 1):
                dp[0][j][1] = 1
            for i in range(1, zero + 1):
                for j in range(1, one + 1):
                    if i > limit:
                        dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1]
                    else:
                        dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1]
                    dp[i][j][0] = (dp[i][j][0] % mod + mod) % mod
                    if j > limit:
                        dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0]
                    else:
                        dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0]
                    dp[i][j][1] = (dp[i][j][1] % mod + mod) % mod
            return (dp[zero][one][0] + dp[zero][one][1]) % mod
    

    ###C

    #define MOD 1000000007
    
    int numberOfStableArrays(int zero, int one, int limit) {
        long long dp[zero + 1][one + 1][2];
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i <= (zero < limit ? zero : limit); ++i) {
            dp[i][0][0] = 1;
        }
        for (int j = 0; j <= (one < limit ? one : limit); ++j) {
            dp[0][j][1] = 1;
        }
        for (int i = 1; i <= zero; ++i) {
            for (int j = 1; j <= one; ++j) {
                if (i > limit) {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
                } else {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                }
                dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
                if (j > limit) {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
                } else {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                }
                dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
            }
        }
        int result = (dp[zero][one][0] + dp[zero][one][1]) % MOD;
        return result;
    }
    

    ###JavaScript

    const MOD = 1000000007;
    
    var numberOfStableArrays = function(zero, one, limit) {
        const dp = Array.from({ length: zero + 1 }, () =>
            Array.from({ length: one + 1 }, () => [0, 0])
        );
    
        for (let i = 0; i <= Math.min(zero, limit); i++) {
            dp[i][0][0] = 1;
        }
        for (let j = 0; j <= Math.min(one, limit); j++) {
            dp[0][j][1] = 1;
        }
    
        for (let i = 1; i <= zero; i++) {
            for (let j = 1; j <= one; j++) {
                if (i > limit) {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
                } else {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                }
                dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
                if (j > limit) {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
                } else {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                }
                dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
            }
        }
        return (dp[zero][one][0] + dp[zero][one][1]) % MOD;
    };
    

    ###TypeScript

    const MOD = 1000000007;
    
    function numberOfStableArrays(zero: number, one: number, limit: number): number {
        const dp: number[][][] = Array.from({ length: zero + 1 }, () =>
            Array.from({ length: one + 1 }, () => [0, 0])
        );
    
        for (let i = 0; i <= Math.min(zero, limit); i++) {
            dp[i][0][0] = 1;
        }
        for (let j = 0; j <= Math.min(one, limit); j++) {
            dp[0][j][1] = 1;
        }
    
        for (let i = 1; i <= zero; i++) {
            for (let j = 1; j <= one; j++) {
                if (i > limit) {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
                } else {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                }
                dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
                if (j > limit) {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
                } else {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                }
                dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
            }
        }
        return (dp[zero][one][0] + dp[zero][one][1]) % MOD;
    };
    

    ###Rust

    const MOD: i32 = 1000000007;
    
    impl Solution {
        pub fn number_of_stable_arrays(zero: i32, one: i32, limit: i32) -> i32 {
            let mut dp = vec![vec![vec![0; 2]; one as usize + 1]; zero as usize + 1];
    
            for i in 0..=zero.min(limit) as usize {
                dp[i][0][0] = 1;
            }
            for j in 0..=one.min(limit) as usize {
                dp[0][j][1] = 1;
            }
    
            for i in 1..=zero as usize {
                for j in 1..=one as usize {
                    if i > limit as usize {
                        dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit as usize - 1][j][1];
                    } else {
                        dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                    }
                    dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
                    if j > limit as usize {
                        dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit as usize - 1][0];
                    } else {
                        dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                    }
                    dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
                }
            }
            (dp[zero as usize][one as usize][0] + dp[zero as usize][one as usize][1]) % MOD
        }
    }
    

    复杂度分析

    • 时间复杂度:$O(\textit{zero} \times \textit{one})$,其中 $\textit{zero}$ 和 $\textit{one}$ 分别为 $0$ 和 $1$ 的出现次数。

    • 空间复杂度:$O(\textit{zero} \times \textit{one})$。

    逐步优化 DP 状态

    作者 tsreaper
    2024年4月28日 00:23

    前记:读了读别人的题解,感觉 newhar 老师的思路更清晰易懂一点,推荐大家看 newhar 的题解,这里就记一下自己的解法。

    解法:DP

    以下题解中把 limit 简记为 $l$。

    转化题目条件

    首先,题目要求序列中恰好出现 zero 个 $0$ 以及 one 个 $1$,显然序列的长度必须为 zero + one。记序列的长度为 $n$。

    只要一个子数组包含 $0$ 和 $1$,那么所有完全包含它的子数组也会包含 $0$ 和 $1$。因此,题目中“arr 中每个长度超过 $l$ 的子数组都同时包含 $0$ 和 $1$”这一条件可以重写为:

    arr 中每个长度恰为 $(l + 1)$ 的子数组都同时包含 $0$ 和 $1$。

    设计 DP 状态

    考虑任一下标 $i$,假设 $i$ 左边最近的 $0$ 到 $i$ 的距离是 $p_i$($p_i = 0$ 说明 arr[i] == 0),$i$ 左边最近的 $1$ 到 $i$ 的距离是 $q_i$($q_i = 0$ 说明 arr[i] == 1)。不妨假设下标 $i$ 是某个长度为 $(l + 1)$ 的子数组的右端点,因为这个子数组里既有 $0$ 又有 $1$,那么我们同时有 $p_i \le l$ 以及 $q_i \le l$。

    由此可以设计出朴素的 DP 状态。设 $f(i, j, p, q)$ 表示考虑序列的前 $i$ 个元素中有 $j$ 个 $1$,且 $i$ 到最近的 $0$ 距离为 $p$,到最近的 $1$ 距离为 $q$ 的方案数。但这样状态总数为 $\mathcal{O}(n^2l^2)$,无论是 C 题还是 D 题都无法通过。

    优化 DP 状态

    注意到元素要么是 $0$ 要么是 $1$,也就是说对于任意的 $i$,$p = 0$ 和 $q = 0$ 恰有一个成立。因此可以将 DP 状态压缩为 $f(i, j, t = 0/1, d)$ 表示考虑序列的前 $i$ 个元素中有 $j$ 个 $1$,且第 $i$ 个元素填的是 $t$,$i$ 到最近的另一种元素(即 $1 - t$)距离为 $d$ 的方案数。这样状态总数为 $\mathcal{O}(n^2l)$。

    转移方程分为两部分。

    f(i, j, 0, d) += f(i - 1, j, 0, d - 1)
    f(i, j, 1, d) += f(i - 1, j - 1, 1, d - 1)
    

    这一部分的含义是,让第 $i$ 个元素和第 $(i - 1)$ 个元素相同,那么到另一种元素的距离自然增加 $1$。

    f(i, j, 0, 1) += f(i - 1, j, 1, *)
    f(i, j, 1, 1) += f(i - 1, j - 1, 0, *)
    

    这一部分的含义是,让第 $i$ 个元素和第 $(i - 1)$ 个元素不同,那么到另一种元素(也就是上一个元素)的距离就是 $1$。这里的星号通过维护前缀和即可 $\mathcal{O}(1)$ 计算。

    初值就是枚举第一个元素填 $0$ 还是 $1$。对于第一个元素来说,另一种元素已经 $1$ 个位置没出现了,所以 $d = 1$,即 $f(1, 0, 0, 1) = f(1, 1, 1, 1) = 1$。

    整体复杂度 $\mathcal{O}(n^2l)$,可以通过 C 题。

    继续优化 DP 状态

    我们发现,DP 主要的运算复杂度来自转移方程的第一部分。第一部分的转移方程看起来很简单,好像只是把上一个位置所有 $(d - 1)$ 的 DP 值都照搬过来而已。由于 $d \le l$ 的限制,只是丢弃了 $f(i - 1, j, *, l)$ 的 DP 值。而 DP 方程的第二部分没有丢弃任何 DP 值,通过前缀和直接把所有情况照单全收。

    这里其实在暗示我们:只要上个位置距离另一种元素的距离不到 $l$,那么当前位置无论填什么都是安全的。只有上个位置距离另一种元素的距离恰为 $l$ 时,当前位置必须填与上个位置不同的元素。也就是说:

    (当前位置填元素 t 的方案数) = (上个位置的所有方案数) - (元素 1 - t 最近一次在 i - limit - 1 出现,从 i - limit 到 i 全部都是元素 t 的方案数)
    

    设 $f(i, j, t = 0/1)$ 表示考虑序列的前 $i$ 个元素中有 $j$ 个 $1$,且第 $i$ 个元素填的是 $t$ 的方案数。“元素 $(1 - t)$ 最近一次在 $(i - l - 1)$ 出现,从 $(i - l)$ 到 $i$ 全部都是元素 $t$ 的方案数”怎么算呢?当然就是 $f(i - l - 1, j', 1 - t)$。这里 $j'$ 要看如果 $t = 0$ 那么 $j' = j$,否则如果 $t = 1$ 那么由于从 $(i - l)$ 到 $i$ 全部都是 $1$,则 $j' = j - l - 1$。

    由此得到转移方程.

    f(i, j, 0) = f(i - 1, j, 0) + f(i - 1, j, 1) - f(i - l - 1, j, 1)
    f(i, j, 1) = f(i - 1, j - 1, 0) + f(i - 1, j - 1, 1) - f(i - l - 1, j - l - 1, 0)
    

    整体复杂度 $\mathcal{O}(n^2)$,可以通过 D 题。

    但是,实现过程中有一个初值的细节问题。当 $i = l + 1$ 时,我们要求 “元素 $(1 - t)$ 最近一次在下标 $0$ 出现的方案数”。空序列一定是合法的,所以有 $f(0, 0, 0) = f(0, 0, 1) = 1$。然而当 $i = 1$ 的时候,这样的初值设置会导致 $f(i - 1, j, 0) + f(i - 1, j, 1)$ 这部分的转移方程出现重复计算,所以我们直接继续设置初值 $f(1, 0, 0) = f(1, 1, 1) = 1$。

    参考代码(c++)

    ###c++

    class Solution {
    public:
        int numberOfStableArrays(int zero, int one, int limit) {
            const int MOD = 1e9 + 7;
            int n = zero + one;
    
            long long g[n + 1][one + 1][2];
            memset(g, 0, sizeof(g));
            g[0][0][0] = g[0][0][1] = g[1][0][0] = g[1][1][1] = 1;
    
            auto update = [&](long long &x, long long y) {
                x = (x + y) % MOD;
            };
    
            for (int i = 2; i <= n; i++) {
                for (int j = 0; j <= one; j++) {
                    update(g[i][j][0], g[i - 1][j][1] + g[i - 1][j][0]);
                    if (i > limit) update(g[i][j][0], MOD - g[i - 1 - limit][j][1]);
    
                    if (j > 0) update(g[i][j][1], g[i - 1][j - 1][0] + g[i - 1][j - 1][1]);
                    if (i > limit && j > limit) update(g[i][j][1], MOD - g[i - 1 - limit][j - 1 - limit][0]);
                }
            }
    
            return (g[n][one][0] + g[n][one][1]) % MOD;
        }
    };
    

    每日一题-找出不同的二进制字符串🟡

    2026年3月8日 00:00

    给你一个字符串数组 nums ,该数组由 n互不相同 的二进制字符串组成,且每个字符串长度都是 n 。请你找出并返回一个长度为 n 且 没有出现nums 中的二进制字符串如果存在多种答案,只需返回 任意一个 即可。

     

    示例 1:

    输入:nums = ["01","10"]
    输出:"11"
    解释:"11" 没有出现在 nums 中。"00" 也是正确答案。
    

    示例 2:

    输入:nums = ["00","01"]
    输出:"11"
    解释:"11" 没有出现在 nums 中。"10" 也是正确答案。
    

    示例 3:

    输入:nums = ["111","011","001"]
    输出:"101"
    解释:"101" 没有出现在 nums 中。"000"、"010"、"100"、"110" 也是正确答案。

     

    提示:

    • n == nums.length
    • 1 <= n <= 16
    • nums[i].length == n
    • nums[i] '0''1'
    • nums 中的所有字符串 互不相同

    5851. 找出不同的二进制字符串 - 模拟

    作者 MGAronya
    2021年8月22日 15:28

    5851. 找出不同的二进制字符串

    第二道题。

    给了咱几个二进制的字符串,要我们返回一个没有出现等长二进制字符串

    想法比较简单,我们把出现的字符串都放进set里方便查找,然后遍历长度为n的二进制字符串,输出第一个没出现的即可。

    因为遍历时要做二进制字符串的+1操作,涉及一点string的大数模拟,做过的应该都觉得蛮简单的。

    才第二题,别想太多,写就完事了!

    模拟

    `
    ###c++

    class Solution {
    public:
        int n;
        string findDifferentBinaryString(vector<string>& nums) {
            n = nums.size();
            set<string> myhash;  //字符串集合
            for(auto s: nums) myhash.insert(s);  //把每个字符串都放入set
            string ans(n, '0');
            while(myhash.find(ans) != myhash.end()) add(ans);  //遍历到第一个找不到的字符串
            return ans;
        }
        void add(string& s){
            bool flag = true;  //表示进位
            for(int i = 0; i < n; ++i){
                if(flag){
                    if(s[i] == '0'){  //0的进位处理
                        s[i] = '1';
                        flag = false;
                    }else s[i] = '0';  //1的进位处理
                }else break; //没有进位,退出循环
            }
        }
    };
    

    康托对角线

    作者 seedjyh
    2021年8月22日 12:24

    解题思路

    只要和第i个串下标i的字符nums[i][i]不同,构造出来的串就和所有的串都不同。

    只限于串数不超过串长的情况。

    时间复杂度O(n)

    代码

    ###cpp

    class Solution {
    public:
        string findDifferentBinaryString(vector<string>& nums) {
            string ans;
            int n = nums.size();
            for (int i = 0; i < n; i++) {
                if (nums[i][i] == '0') {
                    ans += '1';
                } else {
                    ans += '0';
                }
            }
            return ans;
        }
    };
    

    两种方法:暴力枚举 / 康托对角线(Python/Java/C++/Go)

    作者 endlesscheng
    2021年8月22日 12:13

    方法一:暴力枚举

    把 $\textit{nums}$ 中的字符串转成二进制整数,保存到一个哈希集合中。

    枚举 $\textit{ans} = 0,1,2,\ldots$ 直到 $\textit{ans}$ 不在哈希集合中,即为答案。

    方法二告诉我们,满足要求的答案是一定存在的。

    class Solution:
        def findDifferentBinaryString(self, nums: List[str]) -> str:
            st = {int(s, 2) for s in nums}
    
            ans = 0
            while ans in st:
                ans += 1
    
            n = len(nums)
            return f"{ans:0{n}b}"
    
    class Solution {
        public String findDifferentBinaryString(String[] nums) {
            Set<Integer> set = new HashSet<>();
            for (String s : nums) {
                set.add(Integer.parseInt(s, 2));
            }
    
            int ans = 0;
            while (set.contains(ans)) {
                ans++;
            }
    
            String bin = Integer.toBinaryString(ans);
            return "0".repeat(nums.length - bin.length()) + bin;
        }
    }
    
    class Solution {
    public:
        string findDifferentBinaryString(vector<string>& nums) {
            unordered_set<int> st;
            for (auto& s : nums) {
                st.insert(stoi(s, nullptr, 2));
            }
    
            int ans = 0;
            while (st.contains(ans)) {
                ans++;
            }
    
            int n = nums.size();
            return bitset<32>(ans).to_string().substr(32 - n);
        }
    };
    
    func findDifferentBinaryString(nums []string) string {
    n := len(nums)
    has := make(map[int]bool, n)
    for _, s := range nums {
    x, _ := strconv.ParseInt(s, 2, 64)
    has[int(x)] = true
    }
    
    ans := 0
    for has[ans] {
    ans++
    }
    
    return fmt.Sprintf("%0*b", n, ans)
    }
    

    复杂度分析

    • 时间复杂度:$\mathcal{O}(n^2)$,其中 $n$ 是 $\textit{nums}$ 的长度。把长为 $n$ 的字符串转成整数需要 $\mathcal{O}(n)$ 的时间。
    • 空间复杂度:$\mathcal{O}(n)$。

    方法二:康托对角线

    这个方法灵感来自数学家康托关于「实数是不可数无限」的证明。

    例如 $\textit{nums} = [\texttt{111}, \texttt{011}, \texttt{000}]$。我们可以构造一个字符串 $\textit{ans}$,满足:

    • $\textit{ans}[0] = \texttt{0} \ne \textit{nums}[0][0]$。
    • $\textit{ans}[1] = \texttt{0} \ne \textit{nums}[1][1]$。
    • $\textit{ans}[2] = \texttt{1} \ne \textit{nums}[2][2]$。

    $\textit{ans} = \texttt{001}$ 和每个 $\textit{nums}[i]$ 都至少有一个字符不同,满足题目要求。

    一般地,令 $\textit{ans}[i] = \textit{nums}[i][i]\oplus 1$,即可满足要求。其中 $\oplus$ 是异或运算。

    class Solution:
        def findDifferentBinaryString(self, nums: List[str]) -> str:
            ans = [''] * len(nums)
            for i, s in enumerate(nums):
                ans[i] = '1' if s[i] == '0' else '0'
            return ''.join(ans)
    
    class Solution {
        public String findDifferentBinaryString(String[] nums) {
            int n = nums.length;
            char[] ans = new char[n];
            for (int i = 0; i < n; i++) {
                ans[i] = (char) (nums[i].charAt(i) ^ 1);
            }
            return new String(ans);
        }
    }
    
    class Solution {
    public:
        string findDifferentBinaryString(vector<string>& nums) {
            int n = nums.size();
            string ans(n, 0);
            for (int i = 0; i < n; i++) {
                ans[i] = nums[i][i] ^ 1;
            }
            return ans;
        }
    };
    
    func findDifferentBinaryString(nums []string) string {
    ans := make([]byte, len(nums))
    for i, s := range nums {
    ans[i] = s[i] ^ 1
    }
    return string(ans)
    }
    

    复杂度分析

    • 时间复杂度:$\mathcal{O}(n)$,其中 $n$ 是 $\textit{nums}$ 的长度。注意这个方法没有遍历整个字符串,只访问了每个字符串的其中一个字符。
    • 空间复杂度:$\mathcal{O}(1)$,返回值不计入。

    分类题单

    如何科学刷题?

    1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
    2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
    3. 单调栈(基础/矩形面积/贡献法/最小字典序)
    4. 网格图(DFS/BFS/综合应用)
    5. 位运算(基础/性质/拆位/试填/恒等式/思维)
    6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
    7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
    8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
    9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
    10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
    11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
    12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

    我的题解精选(已分类)

    欢迎关注 B站@灵茶山艾府

    简单题,简单做(Python/Java/C++/C/Go/JS/Rust)

    作者 endlesscheng
    2026年3月6日 08:12

    注意 $s$ 不含前导零,那么只含一段连续 $\texttt{1}$ 的 $s$ 只有两种情况:

    • $s$ 全是 $\texttt{1}$。
    • $s$ 是 $\texttt{11}\cdots\texttt{100}\cdots\texttt{0}$,一段 $\texttt{1}$ 和一段 $\texttt{0}$。

    如果 $s$ 包含多段连续的 $\texttt{1}$,比如示例 1 的 $s = \texttt{1001}$, $\texttt{0}$ 的后面还有 $\texttt{1}$。所以检查 $s$ 是否包含 $\texttt{01}$ 即可。

    :只有一个 $\texttt{1}$ 也算一段连续的 $\texttt{1}$。

    ###py

    class Solution:
        def checkOnesSegment(self, s: str) -> bool:
            return "01" not in s
    

    ###java

    class Solution {
        public boolean checkOnesSegment(String s) {
            return !s.contains("01");
        }
    }
    

    ###cpp

    class Solution {
    public:
        bool checkOnesSegment(string s) {
            return s.find("01") == string::npos;
        }
    };
    

    ###c

    bool checkOnesSegment(char* s) {
        return strstr(s, "01") == NULL;
    }
    

    ###go

    func checkOnesSegment(s string) bool {
    return !strings.Contains(s, "01")
    }
    

    ###js

    var checkOnesSegment = function(s) {
        return !s.includes("01");
    };
    

    ###rust

    impl Solution {
        pub fn check_ones_segment(s: String) -> bool {
            !s.contains("01")
        }
    }
    

    复杂度分析

    • 时间复杂度:$\mathcal{O}(n)$,其中 $n$ 是 $s$ 的长度。
    • 空间复杂度:$\mathcal{O}(1)$。

    分类题单

    如何科学刷题?

    1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
    2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
    3. 单调栈(基础/矩形面积/贡献法/最小字典序)
    4. 网格图(DFS/BFS/综合应用)
    5. 位运算(基础/性质/拆位/试填/恒等式/思维)
    6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
    7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
    8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
    9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
    10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
    11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
    12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

    我的题解精选(已分类)

    欢迎关注 B站@灵茶山艾府

    每日一题-检查二进制字符串字段🟢

    2026年3月6日 00:00

    给你一个二进制字符串 s ,该字符串 不含前导零

    如果 s 包含 零个或一个由连续的 '1' 组成的字段 ,返回 true 。否则,返回 false

     

    示例 1:

    输入:s = "1001"
    输出:false
    解释:由连续若干个 '1' 组成的字段数量为 2,返回 false
    

    示例 2:

    输入:s = "110"
    输出:true

     

    提示:

    • 1 <= s.length <= 100
    • s[i]'0''1'
    • s[0]'1'

    【宫水三叶】简单模拟题

    作者 AC_OIer
    2022年10月3日 08:33

    模拟

    根据题意进行模拟即可。

    代码:

    ###Java

    class Solution {
        public boolean checkOnesSegment(String s) {
            int n = s.length(), cnt = 0, idx = 0;
            while (idx < n && cnt <= 1) {
                while (idx < n && s.charAt(idx) == '0') idx++;
                if (idx < n) {
                    while (idx < n && s.charAt(idx) == '1') idx++;
                    cnt++;
                }
            }
            return cnt <= 1;
        }
    }
    

    ###TypeScript

    function checkOnesSegment(s: string): boolean {
        let n = s.length, cnt = 0, idx = 0
        while (idx < n && cnt <= 1) {
            while (idx < n && s[idx] == '0') idx++
            if (idx < n) {
                while (idx < n && s[idx] == '1') idx++
                cnt++
            }
        }
        return cnt <= 1
    };
    

    ###Python

    class Solution:
        def checkOnesSegment(self, s: str) -> bool:
            n, cnt, idx = len(s), 0, 0
            while idx < n and cnt <= 1:
                while idx < n and s[idx] == '0':
                    idx += 1
                if idx < n:
                    while idx < n and s[idx] == '1':
                        idx += 1
                    cnt += 1
            return cnt <= 1
    
    • 时间复杂度:$O(n)$
    • 空间复杂度:$O(1)$
    ❌
    ❌