/*
* 题目描述:
* 给出一个长度为n的01串,现在请你找到两个区间,使得这两个
* 区间中0和1的个数相同。
* 两个区间可以相交,但是不可以完全重叠,即两个区间的左右端点
* 不可以完全相同。
* 现在请你找到两个最长的区间,满足以上要求。
* 即假设第一个区间为[s1, t1],区间内有x个0,有y个1,第二个区间
* 为[s2, t2],区间内也要有个x个0和y个1且没有比这两个区间更长的满足
* 这个要求的区间
*
* 输入描述:
* 输入在一行中给出一个只包含0和1的字符串a。
* 3 < |a| <= 10的6次方
* 输出描述:
* 输出四个整数:s1,t1,s2和t2
* 第一个区间的左右端点编号,以及第二个区间的左右端点编号,字符串从1开始
* 编号。
* 如果有多种满足条件的区间,输出任意两个即可。输入保证答案存在。
*
* 示例1:
* 输入:
* 11011
* 输出:
* 1 4 2 5
* 说明:
* 第一个区间的串为1101,第二个串为1011,显然第一个串和第二个串包含的0和1的个数相同
* 第二个串包含的0和1的个数相同
* 示例2:
* 输入:
* 101
* 输出:
* 1 2 2 3
* 说明:
* 第一个区间的串为10,第二个区间的串为01,显然包含的0和1的个数相同
*/
说明:百度0914第二题,最后15分钟暴力破解88%,运气还算好
解题思路:
要寻找两个不完全相同的区间,有同样多的x和y,说明两区间长度相同,所以左端点和右端点一定不相同。判断区间内的x和y的个数是否相同,可以计算两个相同长度区间内的和是否相等来判断。
1、将字符串中的01字符存储在数组中,并将数组的数字更新为前缀和,比如nums[i]存储前i个数字的和;
2、暴力破解,固定区间大小,从n-1的大小开始遍历,第一次遇到两个区间和相等,就返回。
代码如下:
#include<iostream>
#include<vector>
using namespace std;
vector<int> solution(vector<int>& nums) {
//
int n = nums.size();
int len1, len2; // 记录两个长度
// 因为要找一个最大的相同的两个区间
// 所以要从区间为n-1开始遍历,区间为n只有一个区间,不满足两个区间不能完全相同
// 遇到第一个满足条件的就跳出,返回
for (int i = n - 1; i > 0; --i) {
//第一个区间的右端点从[i-1, n-1]
for (int j = i - 1; j < n; ++j) {
// 第二个区间的右端点从[j+1, n-1]
for (int k = j + 1; k < n; ++k) {
if (j == i - 1) {
len1 = nums[j];
}
else {
// 求 j-i+1到j区间内的和
len1 = nums[j] - nums[j - i];
}
len2 = nums[k] - nums[k - i];
if (len1 == len2) return vector<int>{j - i + 2, j+1, k-i+2, k+1};
}
}
}
return {};
}
int main() {
string s;
cin >> s;
int n = s.size();
vector<int> nums(n, 0);
nums[0] = s[0] - '0';
// 得到数组的前缀和
// 11011 -> 12234
for (int i = 1; i < n; ++i) {
nums[i] = s[i] - '0';
nums[i] += nums[i - 1];
}
vector<int> res = solution(nums);
for (int i = 0; i < res.size(); ++i) {
if (i == 0) {
cout << res[i];
continue;
}
cout << " " << res[i];
}
}