数组中01,可以将数组的一段翻转(0 变 1, 1 变 0),求翻转后数组最多1的个数

这篇博客探讨了一种解决数组中0和1翻转以最大化1的个数的方法。核心思想是构建辅助数组b[],使得b[i] = -1 * a[i],然后寻找b[]的最长子段和,这个子段对应的区间即为最优翻转区间。通过这种方法,可以有效地找到使1的总数增加的翻转区间。

这道题的关键思想:

  • 翻转 0 变 1 ,相当于让 1 的个数 +1
  • 翻转 1 变 0 ,相当与让 1 的个数 -1

解题思路:
根据原来的数组 a[] 构造一个新的数组 b[]

  • a[i] = 0b[i] = 1
  • a[i] = 1b[i] = -1

b[] 求最长子段和,包含最长子段和的区间就是进行01翻转的区间。
代码略

我们来解决这个问题。 ## 题意理解 我们有一个由 `0` 和 `1` 构成的字符串。我们需要**必须翻转一个 `1` 为 `0`**,翻转之后字符串中会有一些连续的 `0` 块,我们统计这些连续 `0` 的长度,然后把它们相乘,这个乘积的**最小值**。 --- ## 解题思路 1. **预处理:** - 找出所有 `1` 的位置。 - 然后尝试将每一个 `1` 翻转为 `0`,模拟翻转后的情况。 2. **模拟翻转:** - 每次将一个 `1` 翻转为 `0`,相当于在这个位置插入一个 `0`。 - 然后统计连续 `0` 的块。 - 将这些块的长度相乘。 3. **注意:** - 要避免整数溢出,使用 `long long`。 - 字符串可能很长(10000位),所以要使用高效的遍历方式。 --- ## C++ 实现代码如下: ```cpp #include <iostream> #include <vector> #include <string> #include <climits> #include <cmath> using namespace std; // 计算翻转一个1后的0块乘积 long long calculateProductAfterFlip(const string& s, int flipIndex) { string modified = s; modified[flipIndex] = '0'; // 模拟翻转 vector<long long> zeroGroups; long long count = 0; // 统计连续0的块 for (char c : modified) { if (c == '0') { count++; } else { if (count > 0) { zeroGroups.push_back(count); count = 0; } } } if (count > 0) zeroGroups.push_back(count); // 最后一个块 if (zeroGroups.empty()) return 0; // 没有0的情况 long long product = 1; for (long long len : zeroGroups) { product *= len; } return product; } int main() { string s; cin >> s; long long minProduct = LLONG_MAX; // 遍历每个1的位置,尝试翻转 for (int i = 0; i < s.size(); ++i) { if (s[i] == '1') { long long product = calculateProductAfterFlip(s, i); minProduct = min(minProduct, product); } } cout << minProduct << endl; return 0; } ``` --- ### 代码解释: - `calculateProductAfterFlip` 函数: - 输入原始字符串和要翻转的 `1` 的索引。 - 模拟翻转为 `0`。 - 遍历字符串统计连续 `0` 的,存储为一个数组。 - 返回这些长度的乘积。 - 主函数中: - 遍历所有字符,找到所有 `1` 的位置。 - 对每个 `1` 进行模拟翻转并计算乘积。 - 保留最小的乘积作为答案。 --- ### 示例说明: 输入: ``` 0000100010000001 ``` 尝试翻转不同的 `1`,得到不同的 `0` 连续块组合,计算它们的乘积,最后取最小值 `40`。 --- ### 时间复杂度分析: - 字符串长度为 `n`,最多有 `n` 个 `1`。 - 每次计算都需要遍历整个字符串(O(n)),所以总时间复杂度是 O(n^2)。 - 由于 n 最大为 10000,n^2 = 1e8,在时间限制 1s 内是可以接受的。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值