我写了一个代码来查找较大字符串中最大子字符串的索引。
当a
和b
的数量相等时,将找到一个子字符串。
例如,给出12
和bbbbabaababb
应该给出2 9
,因为第一个出现的子字符串从索引0开始到索引9结束。3 10
也是答案,但是由于这不是第一个出现的子字符串,因此这不是答案。
我编写的代码是:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
void substr(char str[], int n) {
int sum = 0;
int max = -1, start;
for (int i = 0; i < n; i++) {
if (str[i]=='a') {
str[i] = 0;
} else if(str[i]=='b') {
str[i] = 1;
}
}
// starting point i
for (int i = 0; i < n - 1; i++) {
sum = (str[i] == 0) ? -1 : 1;
// all subarrays from i
for (int j = i + 1; j < n; j++) {
(str[j] == 0) ? (sum += -1) : (sum += 1);
// sum == 0
if (sum == 0 && max < j - i + 1 && n%2==0) {
max = j - i + 1;
start = i-1;
} else if (sum == 0 && max < j - i + 1 && n%2!=0) {
max = j - i + 1;
start = i;
}
}
}
// no subarray
if (max == -1) {
printf("No such subarray\n");
} else {
printf("%d %d\n", start, (start + max - 1));
}
}
/* driver code */
int main(int argc, char* v[]) {
int n; // stores the length of the input
int i = 0; // used as counter
scanf("%d", &n);
n += 1; // deals with the /0 at the end of a str
char str[n]; // stores the total
/* adding new numbers */
while(i < n) {
char new;
scanf("%c", &new);
str[i] = new;
++i;
}
substr(str, n);
return 0;
}
它适用于很多值,但不适用于第二个示例(如下所示)。它应该输出2 9
,但给出3 10
。这是有效的子字符串,但不是第一个...
示例输入和输出应为:
Input Input Input
5 12 5
baababb bbbbabaababb bbbbb
Output Output Output
0 5 2 9 No such subarray
答案 0 :(得分:1)
您遇到了一些问题,其中许多问题与数组大小和索引有关。
当您读取数组时,您需要n
个字符。然后,您将n
的值增加以适应空终止符。对字符串进行空终止是一个好主意,但是末尾的'\0'
实际上不是字符串数据的一部分。而是在创建数组时调整数组大小,并明确放置空终止符:
char str[n + 1];
// scan n characters
str[n] = '\0';
在C语言(和其他语言)中,范围由包含性下限定义,但由排除性上界定义:[lo, hi)
。上限hi
不在范围内,范围内有hi - lo
个元素。 (带有n
元素的数组是一种特殊情况,其中有效范围为[0, n)
。)您应该拥护而不是反对这种约定。如果您的输出应该不同,请修改输出,而不是程序中的表示。
(这是您的第一个示例,假设您有五个字符的字符串,实际上是如何读取并认为b
位于第六位的。这是一个明显的错误。)
最大有效子字符串的位置不取决于整个字符串长度是奇数还是偶数!
不需要将所有“ a”和“ b”都转换为0和1的第一遍,它会破坏原始字符串。这不是什么大问题,但请记住这一点。
实际的问题是如何尝试查找子字符串。您的想法是将“ a”加1,然后将“ b”减1,但这是正确的,但是您没有正确地保留总和。对于每个可能的起点i
,您扫描字符串的其余部分并寻找零和。仅当您将每个i
的总和重置为零时,这才起作用。
void substr(char str[], int n)
{
int max = 0;
int start = -1;
for (int i = 0; i + max < n; i++) {
int sum = 0;
for (int j = i; j < n; j++) {
sum += (str[j] == 'a') ? -1 : 1;
if (sum == 0 && max < j - i) {
max = j - i;
start = i;
}
}
}
if (max == 0) {
printf("No such subarray\n");
} else {
printf("%d %d\n", start, start + max);
}
}
为什么要初始化max = 0
而不是-1
?因为首先添加+ 1 / −1,所以您的检查永远找不到max == 0
的子字符串,但是存在优化的可能性:如果您已经找到了一个长子字符串,则无需查看“字符串的结尾”:循环条件i + max < n
将缩短搜索的时间。
(还有另一个原因:通常,大小和索引由无符号类型表示,例如size_t
。如果将0
用作初始值,则代码将适用于无符号类型。)
对于大型数组,该算法并不是最有效的方法,但是它应该可以工作。