1016. 子串能表示从 1 到 N 数字的二进制串
关键词:数学、二进制
题目来源:1016. 子串能表示从 1 到 N 数字的二进制串 - 力扣(Leetcode)
题目描述
T数学
T二进制
给定一个二进制字符串 s
和一个正整数 n
,如果对于 [1, n]
范围内的每个整数,其二进制表示都是 s
的 子字符串 ,就返回 true
,否则返回 false
。
子字符串 是字符串中连续的字符序列。
输入:s = "0110", n = 3
输出:true
输入:s = "0110", n = 4
输出:false
数据范围
1 <= s.length <= 1000
s[i] 不是 '0' 就是 '1'
1 <= n <= 109
问题分析
数学知识:对于所有k位的二进制数(最高位为1,k>1),将其最高位的1去掉并去除前导0后,可以得到所有1~k-1位的二进制数。
对于题目给定的n,必有k满足2k≤n<2k+1,若s中含有[2k-1 , 2k-1]所有的数,也即s中含有所有k位二进制数,则其必定含有所有1~k位的二进制数,剩下的就是判断s中是否含有[2k, n]所有的数(k+1位)。
于是,问题等价于判断s中是否含有所有k位二进制数和部分k+1位二进制数。
k位二进制数共有2k-1 个,所以s至少含有2k-1 个长度为k的01序列,也即m至少为k+2k-1 -1,。
k+1位二进制数共有n-2k +1个,所以s至少含有n-2k +1个长度为k+1的01序列,也即m至少为k+1 + n-2k +1-1,即k+1 + n-2k 。
又因为m最大值为1000,所以k必定超过10,故枚举所有长度为k和k+1的序列,将其加入哈希表,最后判断是否存在[2k-1 , n]所有的数。
当n为1时特殊处理,直接判断s中是否含有1即可。
代码实现
bool queryString(string s, int n) {
// n=1特殊处理
if (n == 1)
return s.find('1') != s.npos;
// n∈[2^k, 2^(k+1)-1]
int k = 31;
while ((1 << --k) >= n);
// 判断长度
if (s.size() < (1 << (k - 1)) + k - 1 ||
s.size() < n - (1 << k) + k + 1)
return false;
// 枚举
auto check = [&](int l, int dn, int up) {
unordered_set<int> f;
int t = 0, m = s.size(), M = (1 << l) - 1;
for (int i = 0; i < m; i++) {
t = ((t << 1) | (s[i] - '0')) & M;
if (t >= dn && t <= up)
f.insert(t);
}
return f.size() == up - dn + 1;
};
return check(k, 1 << (k - 1), (1 << k) - 1) && check(k + 1, 1 << k, n);
}
时间复杂度:O(log(n)+m)
空间复杂度:O(m)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。