为何程序无法识别字符串重复单词?重排数计算出错求助
单词重排计数程序的错误分析与修正
问题场景
需要编写程序:输入整数T后读取T行字符串,输出字符串的单词重排方式数(公式为:总单词数的阶乘 ÷ 每个重复单词出现次数的阶乘的乘积)。现有代码测试时:
- 输入
T=2,第一行字符串"no way no good",输出正确结果12(对应4!/2!); - 第二行字符串
"yes no yes yes no",正确结果应为5!/(3!2!)=10,但程序输出120,明显错误。
错误原因分析
现有代码的核心问题在于重复单词的识别与统计逻辑完全错误,具体如下:
1. 重复单词的匹配逻辑漏洞
代码通过遍历字符,仅当line[k]是空格且line[k+1]等于line[j]时才开始比较后续字符,直到两者同时遇到空格才判定为重复单词。这种方式:
- 会漏掉非相邻的重复单词匹配(比如第一个
yes和第三个yes的匹配可能因为遍历顺序问题被忽略); - 错误地从单词中间字符开始匹配,导致无效比较或漏判。
2. 重复次数的统计逻辑混乱
代码中count变量的处理逻辑完全不符合需求:
- 初始
count=1,每找到一对重复单词就count++,然后用ans / fact(count),接着重置count=0; - 对于出现3次的单词(如测试用例中的
yes),代码会两次触发重复判定,每次除以2!,最终相当于除以2!*2!,而非正确的3!,导致结果错误。
3. 未正确分割单词
代码仅通过统计空格数得到总单词数,但没有将字符串分割为独立单词,无法准确统计每个单词的出现次数,这是所有错误的根源。
修正方案
正确的思路是先分割字符串为单词数组,统计每个单词的出现次数,再按公式计算结果:
修正后的代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> // 计算阶乘,处理n=0的情况(0! = 1) long long fact(int n) { long long result = 1; for (int i = 2; i <= n; i++) { result *= i; } return result; } int main() { int T; scanf("%d", &T); // 清除换行符 getchar(); for (int i = 0; i < T; i++) { char line[200]; fgets(line, sizeof(line), stdin); // 去掉末尾的换行符 line[strcspn(line, "\n")] = '\0'; int word_count = 0; char* words[50]; // 假设最多50个单词 char* ptr = line; // 分割字符串为单词数组 while (*ptr != '\0') { // 跳过开头的空格 while (*ptr == ' ') ptr++; if (*ptr == '\0') break; words[word_count++] = ptr; // 找到单词的结尾(空格或字符串末尾) while (*ptr != ' ' && *ptr != '\0') ptr++; if (*ptr != '\0') { *ptr = '\0'; // 将空格替换为结束符,分割单词 ptr++; } } // 计算总单词数的阶乘 long long ans = fact(word_count); // 统计每个单词的出现次数,并计算除法 int visited[50] = {0}; // 标记已统计的单词 for (int j = 0; j < word_count; j++) { if (visited[j]) continue; int cnt = 1; for (int k = j + 1; k < word_count; k++) { if (strcmp(words[j], words[k]) == 0) { cnt++; visited[k] = 1; } } if (cnt > 1) { ans /= fact(cnt); } } printf("%lld\n", ans); } return 0; }
修正要点
- 分割单词:将字符串分割为独立的单词数组,方便后续统计;
- 正确统计重复次数:遍历单词数组,统计每个单词的出现次数,对次数>1的单词,用总阶乘除以该次数的阶乘;
- 阶乘函数优化:改用循环实现阶乘,同时处理
n=0的情况(0! = 1),避免递归的栈溢出问题; - 输入处理优化:用
fgets读取整行,避免scanf处理换行符的问题。
内容的提问来源于stack exchange,提问作者N Tahseen
相关产品推荐
相关产品推荐

