[英]Is my usage of fgets() and strtok() incorrect for parsing a multi-line input?
我正在编写一个Moore Voting算法的实现,用于在数组中查找多数元素 (即发生超过size/2
次的元素)。 代码应返回多数元素(如果存在),否则应返回-1。 现在我的majorityElement(int size, int arr[])
似乎完全正常,如果我直接硬编码main()
函数中的整数数组并从那里调用它。
int majorityElement(int size, int arr[])
{
int majorityindex = 0;
int votes = 1;
int index;
for (index = 1; index < size; index++)
{
if (arr[index] == arr[majorityindex])
votes++;
else
votes--;
if (votes == 0)
{
majorityindex = index;
votes = 1;
}
}
int count = 0;
int i;
for (i = 0; i < size; i++)
{
if(arr[majorityindex] == arr[i])
count++;
}
if (count > (size/2))
return arr[majorityindex];
return -1;
}
但是,如果我尝试读取这样的输入流,我将面临一些问题:
2
5
3 1 3 3 2
3
1 2 3
输入的第一行包含测试用例的数量。 测试用例的第一行是数组的大小,第二行是数组的元素。
我试图从main()
函数中读取输入流,如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
int majorityElement(int size, int arr[]);
int main()
{
char buf[3];
fgets(buf, MAX, stdin);
int n = atoi(buf);
char a[3];
char b[MAX];
int i;
int count;
int* num;
for (i = 0; i < n; i++)
{
count = 0;
fgets(a, MAX, stdin);
fgets(b, MAX, stdin);
int x = atoi(a);
char* num[x];
int arr[x];
int k = 0;
char* token = strtok(b, " ");
while (token != NULL)
{
num[k] = token;
arr[k] = atoi(num[k]);
token = strtok(NULL, " ");
k++;
}
printf("%d\n", majorityElement(x, arr));
}
return 1;
}
我在声明期间将buf[]
和a[]
的大小取为3
,因为它们必须有足够的空间用于fgets()
读取的\\n
字符以及终止\\0
字符。 据我所知, atoi()
函数在将字符数组(字符串)转换为整数时忽略\\n
字符。 我试图在字符数组buf
存储输入的第一个条目(即条目数),将其转换为字符串并将其存储在变量n
。 类似地,我试图在变量x
获得测试数组的大小,并在整数数组arr
获得测试数组(测试用例的第二行)。 虽然buf
和n
似乎在所有情况下都获得了正确的值,但我不太确定arr
。 我知道fgets()
留下一个终端\\n
字符,这可能会在使用strtok
进行标记化时造成一些破坏,尽管我无法指责原因。 我尝试在GeeksForGeeks上提交此代码。 它为样本测试用例提供了绝对正确的输出:
2
5
3 1 3 3 2
3
1 2 3
那是
3
-1
但是,当我尝试“提交”我的解决方案时,它说:
Possibly your code doesn't work correctly for multiple test-cases (TCs).
The first test case where your code failed:
Input:
4
1 2 2 1
Its Correct output is:
-1
And Your Code's output is:
1
我似乎无法理解这一点。 如果我在stdin
手动写这个:
1
4
1 2 2 1
代码输出
-1
这确实是正确的解决方案。 这与提交期间声明的输出(即1
不匹配。 所以我不确定我哪里出错了。 我在main()
函数中错误地使用了fgets()
或strtok()
吗? 或者是别的什么?
根据评论中的建议更新了main()
函数。
int main()
{
char buf[MAX];
fgets(buf, MAX, stdin);
int n = atoi(buf);
char a[MAX];
char b[MAX];
int i;
int count;
int* num;
for (i = 0; i < n; i++)
{
count = 0;
fgets(a, MAX, stdin);
fgets(b, sizeof(a), stdin);
a[sizeof(a)-1] = '\0';
b[sizeof(b)-1] = '\0';
int x = atoi(a);
int arr[x];
int k = 0;
char* token = strtok(b, " ");
while (token != NULL)
{
if (k > x)
break;
arr[k] = atoi(token);
token = strtok(NULL, " ");
k++;
}
printf("%d\n", majorityElement(x, arr));
}
return 1;
}
正如@Vlad所指出的那样,MAX在原始数组中设置得太低了。 问题是数组中的条目数上限为10^7
,每个数组条目的上限为10^6
(7位)。 所以MAX需要10^8
。 根据评论中的建议,我现在使用动态分配而不是可变长度数组。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 10000000
int majorityElement(int size, int arr[])
{
int majorityindex = 0;
int votes = 1;
int index;
for (index = 1; index < size; index++)
{
if (arr[index] == arr[majorityindex])
votes++;
else
votes--;
if (votes == 0)
{
majorityindex = index;
votes = 1;
}
}
int count = 0;
int i;
for (i = 0; i < size; i++)
{
if(arr[majorityindex] == arr[i])
count++;
}
if (count > (size/2))
return arr[majorityindex];
return -1;
}
int main()
{
char* buf = calloc (MAX, sizeof(char));
fgets(buf, MAX, stdin);
int n = atoi(buf);
char* a = calloc (MAX, sizeof(char));
char* b = calloc(MAX, sizeof(char));
int i;
for (i = 0; i < n; i++)
{
fgets(a, MAX, stdin);
fgets(b, MAX, stdin);
a[strlen(a)-1] = '\0';
b[strlen(b)-1] = '\0';
int x = atoi(a);
int *arr = calloc(x, sizeof(int));
int k = 0;
char* token = strtok(b, " ");
while (token != NULL)
{
if (k > x)
break;
arr[k] = atoi(token);
token = strtok(NULL, " ");
k++;
}
printf("%d\n", majorityElement(x, arr));
free(arr)
}
free(buf);
free(a);
free(b);
return 1;
}
如果我将MAX设置为10^7
那么代码将通过所有测试用例并被接受提交。 但是,如果我将MAX设置为10^8
(根据需要),我会遇到分段错误。 怎么克服这个?
你的程序有几个缺点。
例如,在函数main中有未使用的变量声明为
int count;
int* num;
该函数确实考虑到-1
可以是数组的有效值。
可以在测试中指定的元素数量存在问题。 这是一个非常大的数字(根据描述1 <= N <= 10000000
)。 所以MAX
的值等于100
太低了。 结果,数据可能被错误地读取而不是完全读取。 此外,可变长度阵列也可能出现问题。
不需要使用函数fgets
因为可以使用scanf
读取每个整数。
我可以建议以下解决方案。 试一试,看看它是否会通过测试。
#include <stdio.h>
#include <stdlib.h>
size_t majorityElement( const int a[], size_t n )
{
size_t majority_index = 0;
for ( size_t i = 1, votes = 1; i < n; i++ )
{
if ( a[majority_index] == a[i] )
{
++votes;
}
else
{
--votes;
}
if ( votes == 0 )
{
majority_index = i;
++votes;
}
}
size_t count = 0;
for ( size_t i = 0; i < n; i++ ) count += a[i] == a[majority_index];
return n / 2 < count ? majority_index : n;
}
int main(void)
{
size_t n = 0;
scanf( "%zu", &n );
for ( size_t i = 0; i < n; i++ )
{
size_t m = 0;
scanf( "%zu", &m );
if ( m != 0 )
{
int *a = calloc( m, sizeof( int ) );
for ( size_t j = 0; j < m; j++ ) scanf( "%d", a + j );
size_t majority_index = majorityElement( a, m );
printf( "%d\n", majority_index == m ? -1 : a[majority_index] );
free( a );
}
}
return 0;
}
如果它不通过测试,那么测试中似乎存在一个错误。:)
或者,如果函数返回类型可能未更改,则函数定义可能如下所示
int majorityElement( const int a[], size_t n )
{
size_t majority_index = 0;
for ( size_t i = 1, votes = 1; i < n; i++ )
{
if ( a[majority_index] == a[i] )
{
++votes;
}
else
{
--votes;
}
if ( votes == 0 )
{
majority_index = i;
++votes;
}
}
size_t count = 0;
for ( size_t i = 0; i < n; i++ ) count += a[i] == a[majority_index];
return n / 2 < count ? a[majority_index] : -1;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.