Count number of binary strings without consecutive 1’s

本文探讨了如何计算长度为n且不含连续1的二进制串的数量,提供了两种算法解决方案:一是使用回溯法结合深度优先搜索实现,二是采用更高效的动态规划方法。

一、题目

1. Count number of binary strings without consecutive 1’s

Given a positive integer n(3≤n≤90), count all possible distinct binary strings of length n such that there are no consecutive 1's .
Examples:

  Input:  2 
  Output: 3 // The 3 strings are 00, 01, 10 
  ​
  Input: 3 
  Output: 5 // The 5 strings are 000, 001, 010, 100, 101

二、题意

给定一个正整数n(3≤n≤90),数出长度为n的所有可能的不同二进制串的个数,使得串中没有连续的1出现。

 

三、解题思路及算法

1、回溯+深搜

长度为n的所有二进制串形成一棵子集树,所以可以用DFS遍历子集树,遍历过程中检查是否有连续的1出现,时间复杂度为O(2^n)。

// 深搜回溯法 
#include <iostream>
using namespace std;
long long total = 0;
bool judge(string s){
	int length = s.length();
	int num = 0;
	for(int i=0; i<length-1; i++){
		if(s[i] == '1' && s[i+1] == '1')
			return false;
	}
	return true;
}
void calculate(string s, int index, int n){
	if(index == n) {
		if(judge(s)){total++;} 
		return;
	}
	else{
		calculate(s, index+1, n);
		s[index] = '1';
		calculate(s, index+1, n);
	}
}
int main (){
	int n;
	cin>>n;
	string s="";
	for(int i=0; i<n; i++){
		s+='0';
	}
	calculate(s, 0, n);
	cout<<total<<endl;
	
	return 0;
} 

2、动态规划(DP)
 思路:设a[i-2],a[i-1], a[i]分别为长度为i-2,i-1,i的不含连续1的二进制字符串的个数
 那么从长度为i的来考虑:
 1、若最后一个值为0,则这种情况下不含连续1的二进制字符串个数为a[i-1]
  2、若最后一个值为1,则这种情况下要符合条件那么倒数第二个的值只能为0
   此时符合条件的个数为a[i-2](理由和1相同) 

时间复杂度:O(n)。

#include <iostream>
using namespace std;
int main (){
	int n;
	cin>>n;
	long long a[n+1];   // n最大为90,那么总数的量级是2^90数量级,因此需要大数 
	a[1] = 2; a[2] = 3;
	for(int i=3; i<=n; i++){
		a[i] = a[i-1] + a[i-2];
	}
	cout<<a[n]<<endl;
	
	return 0;
} 

参考博文:https://blog.youkuaiyun.com/climber16/article/details/81604342

T-2 Binary String and Score 分数 35 作者 曹鹏 单位 Amazon Given a binary string s (contains only characters 0 and 1), here is the way we calculate its score: Cut the string into several groups, each group contains the same character and consecutive groups contain different characters. The score is defined as the exclusive-or value of all the group lengths (if there is only one group, the score is its length). For instance, for string "10001100001", the groups are "1", "000", "11", "0000" and "1". The score is 1 ^ 3 ^ 2 ^ 4 ^ 1 = 5. Now in each step, you can change the string by in swapping any adjacent 2 characters. You can apply as many as steps as you want (possible 0). For each possible score, how many different strings can you get and what's the minimal number of steps to change s into a string with the particular score? Input Specification: Each input file contains one test case. Each case has a single line containing the binary string s (1 ≤ s.length() ≤ 64). Output Specification: For each possible score, output a line containing 3 space-separated integers, namely, the score, the number of different strings with the particular score you can get after changing s as many times as you want, and the minimal number of steps to change s into a string of that score. Output the lines in the score's ascending order. Sample Input: 010 Sample Output: 1 1 0 3 2 1 Hint: There are 3 possible final strings in total. "010" needs has score 1 (1 ^ 1 ^ 1 = 1) and the minimal number of steps to get it is 0. Both "011" and "110" have score 3 (1 ^ 2) and the minimal number of steps to get them is 1. (swap the middle '1' with the character on the left or right side.) 代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB 栈限制 8192 KB
最新发布
07-31
### 问题分析 目标是给定一个二进制字符串 `s`,通过任意次数的相邻字符交换,使其转换为某一特定形式的字符串,并计算该字符串的得分(异或所有连续相同字符的长度),然后统计每个可能得分对应的不同字符串数量,以及将原字符串转换为这些字符串所需的最小交换步数。 #### 核心挑战 1. **字符串变换**:如何通过交换相邻字符将原字符串变为目标字符串,并计算最小交换步数。 2. **得分计算**:如何将字符串分割为连续相同字符的组,并计算各组长度的异或值。 3. **枚举所有可能字符串**:在所有可能的排列中,找到具有不同得分的字符串,并统计数量。 4. **优化交换步数**:对于每个得分,找到将原字符串转换为该得分的最小交换步数。 --- ### 解题思路 1. **枚举所有可能的二进制字符串**:由于 `s.length() ≤ 64`,直接枚举所有 `2^n` 的二进制字符串不可行。但可以基于字符 `0` 和 `1` 的数量进行排列组合生成所有可能字符串。 2. **得分计算**:对每个字符串,按连续字符分组并计算长度的异或值。 3. **最小交换步数**:使用贪心策略,将原字符串与目标字符串对比,计算每个字符需要移动的最小步数。具体做法是:从左到右,若当前字符与目标不一致,则找到最近的目标字符并交换,记录步数。 4. **结果统计**:对每个得分,维护一个字典,记录不同字符串的数量以及最小交换步数。 --- ### C++ 实现 ```cpp #include <iostream> #include <string> #include <vector> #include <map> #include <set> #include <algorithm> #include <queue> #include <climits> using namespace std; // 计算字符串的得分 int calculateScore(const string& s) { int score = 0; char prev = s[0]; int count = 1; for (int i = 1; i < s.size(); ++i) { if (s[i] == prev) { ++count; } else { score ^= count; prev = s[i]; count = 1; } } score ^= count; return score; } // 计算将 s1 转换为 s2 所需的最小交换步数 int minSwaps(const string& s1, const string& s2) { vector<int> pos0, pos1; for (int i = 0; i < s1.size(); ++i) { if (s1[i] == '0') pos0.push_back(i); else pos1.push_back(i); } vector<int> target0, target1; for (int i = 0; i < s2.size(); ++i) { if (s2[i] == '0') target0.push_back(i); else target1.push_back(i); } int res = 0; for (int i = 0; i < target0.size(); ++i) { res += abs(pos0[i] - target0[i]); } for (int i = 0; i < target1.size(); ++i) { res += abs(pos1[i] - target1[i]); } return res; } // 生成所有可能的二进制字符串 void generateAllBinaryStrings(int n, string current, vector<string>& result) { if (current.size() == n) { result.push_back(current); return; } generateAllBinaryStrings(n, current + '0', result); generateAllBinaryStrings(n, current + '1', result); } int main() { string s; cin >> s; int n = s.size(); vector<string> allStrings; generateAllBinaryStrings(n, "", allStrings); map<int, pair<long long, int>> scoreMap; int zeroCount = count(s.begin(), s.end(), '0'); int oneCount = n - zeroCount; for (const string& str : allStrings) { int z = count(str.begin(), str.end(), '0'); int o = n - z; if (z != zeroCount || o != oneCount) continue; int score = calculateScore(str); int swaps = minSwaps(s, str); if (scoreMap.find(score) == scoreMap.end()) { scoreMap[score] = make_pair(1, swaps); } else { scoreMap[score].first += 1; scoreMap[score].second = min(scoreMap[score].second, swaps); } } for (auto& entry : scoreMap) { cout << entry.first << " " << entry.second.first << " " << entry.second.second << endl; } return 0; } ``` --- ### 代码说明 - **`calculateScore`**:按题目定义计算得分。 - **`minSwaps`**:通过贪心策略计算最小交换步数。 - **`generateAllBinaryStrings`**:递归生成所有可能的二进制字符串。 - **主函数逻辑**:枚举所有字符串,过滤字符数量不匹配的,计算得分与交换步数,最后输出结果。 --- ### 性能优化 - 由于直接枚举所有字符串效率较低,可进一步优化为只生成具有相同 `0` 和 `1` 数量的字符串。 - 使用 `next_permutation` 可以更高效地生成所有排列。 --- ### 示例输入输出 输入: ``` 010 ``` 输出: ``` 1 1 0 3 2 1 ``` --- ### 相关问题 1. 如何优化二进制字符串生成过程以减少时间复杂度? 2. 如何在不生成所有字符串的情况下计算所有可能得分? 3. 如何扩展该算法以处理非二进制字符串? 4. 如何验证最小交换步数计算的正确性? 5. 如何将该算法扩展到支持多组得分计算?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值