C++ 生成连续的0和1的最小翻转次数
连续的字符序列可以通过从原始字符串中选择零个或多个字符并按任意顺序而不跳过其中任何字符来创建,这些序列被称为0和1的子字符串。
例如,字符串 “0101” 的后续子字符串是:0,1,01,10,010,101 和 0101。
未填充的字符串也是所有字符串的子字符串,因为它可以通过从原始字符串中选择恰好 0 个字符来生成。
因此,在这个示例中 “” 也是 “0101” 的子字符串。
方法
- 使用动态规划
-
使用贪婪算法
方法1:使用动态规划
动态规划是确定生成连续的0和1的最小翻转次数的有效方法。通过动态规划的方法,将问题划分为较小的子问题并从底向上构建出解决方案。
我们必须确定生成这样的子字符串所需的最小翻转次数。
语法
min (k5):
l8 [0][0] = 0
if k5 [0] == '0'
else 1
l8 [0][1] = 0
if k5 [0] == '1'
else 1
l8[i][0] = l8[i-1][1] + (0 if k5[i] == '0' else 1)
l8[i][1] = l8[i-1][0] + (0 if k5[i] == '1' else 1)
// Returning the minimum required
return minimum among(l8[n-1][0], l8[n-1][1])
步骤
计算生成每个配对字符串中连续的0和1子串所需的翻转数量的计算方法 −
步骤1 − 初始化两个变量flip_zero和flip_one,均设为0。
步骤2 − 建议仔细阅读字符串中的每个字符以确保重复。
- 如果当前字符与前一个字符不匹配,则查看它是’0’还是’1’。
-
如果当前字符为’0’,则将flip_zero增加1。
-
如果当前字符为’1’,则将flip_one增加1。
步骤3 − 返回flip_zero和flip_one中的较小值。
该算法计算改变字符串中0和1所需的翻转次数。根据当前字符的值,每次遇到新字符时,flip_zero或flip_one都会增加。flip_zero和flip_one中的较小值是最终的结果。
示例1
此实现中的minFlips函数迭代字符串s,计算相邻字符不同的情况。这个数字反映了为了生成连续的0和1子串而必须翻转的频率。不需要翻转的次数由这个计数和包含与相邻字符相同的字符的连续的0或1子串的数量的最小值表示。
我们在样本的主要方法中使用字符串”0011100″调用minFlips函数并打印结果,结果为1。根据这个结果,输入字符串中的连续的0和1子串可以通过仅翻转一次来生成。
#include <iostream>
#include <string>
#include <algorithm>
int minFlips (std::string s) {
int n = s.size();
int count = 0;
for (int i = 0; i < n - 1; i++) {
if (s[i]!= s[i+1]) {
count++;
}
}
return std::min(count, n - count - 1);
}
int main () {
std::string s = "0011100";
std::cout << "Minimum flips required: " << minFlips(s) << std::endl;
return 0;
}
输出
Minimum flips required: 2
使用贪心编程
为了得到整体最优解,贪心编程方法要求在每一阶段做出局部最优的决策。找到产生连续的0和1子字符串所需的最小翻转数量是该技术的一种应用。
通常,问题陈述涉及交替出现的0和1子字符串的二进制字符串。目标是确定将字符串转换为所有的0或者所有的1在另一种情况之前出现所需的最小翻转次数。
步骤
为了找到在每个字符串中生成连续的0和1子字符串所需的最小翻转次数,我们可以按照以下算法进行。
- 步骤1 - 我们需要设置两个变量,初始化为0。第一个变量c1代表产生序列010101所需的翻转次数。另一个变量c2表示我们需要执行的翻转次数以创建序列101010。
-
步骤2 - 遍历字符串,对于每个字符,检查是否与当前模式的预期字符匹配。如果不匹配,增加相应的c变量。
-
步骤3 - 检查当前字符后,根据当前模式翻转预期字符。例如,如果当前模式是010101…而当前字符是1,则下一个预期字符将是0。
-
步骤4 - 如果生成相反模式所需的翻转次数少于当前模式,则切换模式。
-
步骤5 - 返回c1和c2中的最小值。
-
步骤6 - 该算法接受输入字符串的长度n,并具有O(n)的时间复杂度。
示例2
在这个示例中,min Flips函数以二进制字符串s作为输入,并输出使得产生交替的0和1的字符串所需的最小翻转次数。该函数通过计算产生每个字符串所需的翻转次数生成两个可能的交替字符串,一个以0开头,另一个以1开头。然后,该函数返回这两个数字中的较小值。
在主函数中,我们使用二进制字符串”0101010101″调用min Flips,并将结果打印到控制台。输出应该是”Minimum flips required: 0″,因为输入字符串已经是交替出现的0和1的字符串。结果应该是”Least flips required: 0″,因为输入字符串已经是交替出现的0和1的字符串。
#include <iostream>
#include <string>
using namespace std;
int minFlips(string s) {
int n = s.length();
int flips1 = 0, flips2 = 0;
// Count flips required to generate string of alternating 0's and 1's
for (int i = 0; i < n; i++) {
if (i % 2 == 0 && s[i] != '0') {
flips1++;
} else if (i % 2 == 1 && s[i] != '1') {
flips1++;
}
if (i % 2 == 0 && s[i] != '1') {
flips2++;
} else if (i % 2 == 1 && s[i] != '0') {
flips2++;
}
}
// Return the minimum number of flips required
return min(flips1, flips2);
}
int main() {
string s = "0101010101";
int flips = minFlips(s);
cout << "Minimum flips required: " << flips << endl;
return 0;
}
输出
Minimum flips required: 0
结论
确定产生连续的由0和1组成的子字符串所需的最小翻转次数的解决方案取决于问题的限制和要求。为了使用最少的翻转操作来实现这一点,取决于字符串和如何定义“连续的”子字符串。在解决问题时通常有多种可能的方法。例如,对于类似的问题,动态规划和贪心算法都是可能的答案。
具体而言,如果你需要找到问题的最佳解决方案,动态规划可能是你的最佳选择。通过这种技术,你可以创建一个数据库,其中包含有关需要多少次翻转操作才能构建有效的子字符串的信息,直到指定的点为止。尽管这种方法确实有其优点,但是要发现此问题的最优解,了解各种解决方案的缺点是至关重要的。