leetcode-1461. 检查一个字符串是否包含所有长度为 K 的二进制子串

该博客介绍了如何解决LeetCode上的1461题,题目要求判断一个二进制字符串是否包含所有长度为k的子串。博主分享了三种不同的解法,包括使用哈希集合、快速幂计算以及滑动窗口技巧,并详细解释了每种方法的时间和空间复杂度。此外,还讲解了C++中`stoi`函数的用法及其注意事项。
摘要由CSDN通过智能技术生成

leetcode-1461. 检查一个字符串是否包含所有长度为 K 的二进制子串
给你一个二进制字符串 s 和一个整数 k 。

如果所有长度为 k 的二进制字符串都是 s 的子串,请返回 true ,否则请返回 false 。

示例 1:
输入:s = “00110110”, k = 2
输出:true
解释:长度为 2 的二进制串包括 “00”,“01”,“10” 和 “11”。
它们分别是 s 中下标为 0,1,3,2 开始的长度为 2 的子串。

本人最笨的办法

class Solution {
public:
    bool hasAllCodes(string s, int k) {
		int len = s.length();
		if(len < k) return false;
        unordered_set<string> us;
		for(int i = 0; i <= len - k; i++) {
			us.insert(s.substr(i, k));
		}
		
		// 快速幂计算 2^k
		int ans = 1;
		long long int cur = 2;
		while(k) {
			if(k&1) {
				ans *= cur;
			}
			
            k >>= 1;
			cur = cur*cur;
		}
		
		return us.size()  == ans;
    }
};

y^0b101 = 1y^0b100 * 0y^0b10 * 1y^0b1
= 1
y^4 * 0y^2 * 1y^1

哈希

【leetcode的官方答案】

如果 s 包含 2^k 个长度为 k 的二进制串,那么它的长度至少为 2^k+k-1

class Solution {
public:
    bool hasAllCodes(string s, int k) {
        if (s.size() < (1 << k) + k - 1) {
            return false;
        }

        unordered_set<string> exists;
        for (int i = 0; i + k <= s.size(); ++i) {
            exists.insert(move(s.substr(i, k))); // move语义不错
        }
        return exists.size() == (1 << k);
    }
};

时间复杂度:O(k * L)
L 是字符串 s 的长度。
将长度为 k 的字符串加入哈希表的时间复杂度为 O(k),即为计算哈希值的时间。

空间复杂度:O(k * 2^k)
哈希表中最多有 2^k 项,每一项是一个长度为 k 的字符串。

哈希表 + 滑动窗口

class Solution {
public:
    bool hasAllCodes(string s, int k) {
        if (s.size() < (1 << k) + k - 1) {
            return false;
        }

        int num = stoi(s.substr(0, k), nullptr, 2);
        unordered_set<int> exists = {num};
        
        for (int i = 1; i <= s.size() - k; ++i) {
			// 加、减 的优先级高于 << 和 >>
			// 所以一定要给 ((s[i - 1] - '0') << (k - 1)) 加括号
			// num = num - ((s[i - 1] - '0') << (k - 1))) * 2 + (s[i + k - 1] - '0');
			num = num * 2 - ((s[i - 1] - '0') << k) + (s[i + k - 1] - '0');
            exists.insert(num);
        }
        return exists.size() == (1 << k);
    }
};

时间复杂度:O(L)
空间复杂度:O(2^k)
哈希表中最多有 2^k 项,每一项是一个十进制整数。

value[s[0,k)] = s[0]*2^(k-1) + s[1]*2^(k-2) + … + s[k-1]*2^(0)
value[s[1,k+1)] = s[1]*2^(k-1) + s[2]*2^(k-2) + … + s[k]*2^(0)
如何从 value[s[0,k)] 推导出 value[s[1,k+1)] :
value[s[1,k+1)] = 2 * (s[1]*2^(k-2) + s[2]*2^(k-3) + … + s[k-1]*2^(0)) + s[k]*2^(0)
= 2 * (s[0]*2^(k-1) + s[1]*2^(k-2) + … + s[k-1]*2^(0) - s[0]*2^(k-1)) + s[k]*2^(0)
= 2 * value[s[0,k)] - s[0]*2^k + s[k]
所以:
当知道 value[s[i-1,k+i-1)] 后,value[s[i,k+i)] 的计算如下:
value[s[i,k+i)] = 2 * value[s[i-1,k+i-1)] - s[i-1]*2^k + s[k + i - 1]

num = num * 2 - s[i-1] * 2^k + s[k + i - 1]
2^k = 1 << k;

stoi 和 atoi 的学习

atoi()的参数是 const char* , 对于一个字符串str必须调用 c_str()把这个string转换成 const char类型,
stoi()的参数是 const string
, 不需要转化为 const char*;
stoi()会做范围检查,默认范围在int的范围内,如果超出范围的话则会runtime error!
atoi()不会做范围检查,如果超出范围的话,超出上界,则输出上界,超出下界,则输出下界;

int stoi (const string&  str, size_t* idx = 0, int base = 10);

Convert string to integer
Parses str interpreting its content as an integral number of the specified base, which is returned as an int value.
If idx is not a null pointer, the function also sets the value of idx to the position of the first character in str after the number.
The function uses strtol (or wcstol) to perform the conversion.

// stoi example
#include <iostream>   // std::cout
#include <string>     // std::string, std::stoi

int main ()
{
  std::string str_dec = "2001, A Space Odyssey";
  std::string str_hex = "40c3";
  std::string str_bin = "-10010110001";
  std::string str_auto = "0x7f";

  std::string::size_type sz;   // alias of size_t

  int i_dec = std::stoi (str_dec,&sz); // sz 指向数字完之后的数字
  int i_hex = std::stoi (str_hex,nullptr,16);
  int i_bin = std::stoi (str_bin,nullptr,2);
  int i_auto = std::stoi (str_auto,nullptr,0);

  // str_dec.substr(sz) 指的是str_dec从sz开始到结尾的字符串
  std::cout << str_dec << ": " << i_dec << " and [" << str_dec.substr(sz) << "]\n";
  std::cout << str_hex << ": " << i_hex << '\n';
  std::cout << str_bin << ": " << i_bin << '\n';
  std::cout << str_auto << ": " << i_auto << '\n';

  return 0;
}

#include <iostream>   // std::cout
#include <string>     // std::string, std::stoi

int main ()
{
  std::string str_dec = "2147483647abc";
  std::string::size_type sz;   // alias of size_t
  int i_dec = std::stoi (str_dec,&sz); // sz 指向数字完之后的字符
  // 2147483647 and [abc]
  std::cout << str_dec << ": " << i_dec << " and [" << str_dec.substr(sz) << "]\n";
  return 0;
}

如果是 2147483647123 就runtime error了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值