You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Codeforces 39J提交失败求助:样例通过但评测不通过,逻辑错误排查

Codeforces 39J提交失败求助:样例通过但评测不通过,逻辑错误排查

看起来你遇到了典型的“样例过了但评测挂了”的坑,这种情况通常是代码逻辑没覆盖到边界case,或者有致命的输入处理错误,咱们一步步来捋你的问题:

你的问题背景回顾

给定两个小写单词,其中一个恰好比另一个长1个字符。需要判断:从长单词中删除一个字符后是否能得到短单词,若可以则输出所有满足条件的1-based位置;若不行输出0。你的程序采用正向+反向扫描的逻辑,能通过给定样例,但提交后评测不通过。

你的代码核心错误分析

我看完你的代码后,发现了3个致命/严重的逻辑漏洞:

1. 未处理输入顺序反转的情况

你的代码直接假设第一个输入是长单词、第二个是短单词,但题目只说“其中一个比另一个长1”,完全可能出现输入顺序反过来的情况(比如输入a aa)。这会导致你访问数组越界(比如短单词长度比长单词大时,循环会访问long_word的超出长度的位置),触发未定义行为,直接导致评测失败。

2. 连续重复字符的边界情况处理错误

比如测试用例:

  • 长单词:aabaaa(长度6)
  • 短单词:abaaa(长度5)
    正确输出应该是2,然后1 2(删除第1或第2个a都能得到短单词)。但你的代码会进入forward_misspelled && !reverse_misspelled分支,直接输出11,漏了第二个有效位置。

3. 反向扫描的位置判断逻辑不严谨

你的反向扫描在找到第一个不匹配的位置后直接break,没有考虑到当反向全匹配时的情况(比如长单词是aaaaa,短单词是aaaa),虽然这部分你处理了,但结合正向扫描的逻辑时,对有效位置的收集范围判断错误。

修正后的代码及逻辑说明

我基于你的核心思路(正向+反向扫描),修正了所有漏洞,代码如下:

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>

#define MAX_LETTERS 1000000

int main(void) {
    char word1[MAX_LETTERS + 1];
    char word2[MAX_LETTERS + 1];
    scanf("%s%s", word1, word2);

    int len1 = strlen(word1);
    int len2 = strlen(word2);
    char *long_word, *short_word;
    int n; // 短单词长度

    // 第一步:确保long_word是长单词,short_word是短单词,长度差必须为1
    if (len1 == len2 + 1) {
        long_word = word1;
        short_word = word2;
        n = len2;
    } else if (len2 == len1 + 1) {
        long_word = word2;
        short_word = word1;
        n = len1;
    } else {
        // 长度差不是1,直接输出0
        printf("0\n");
        return 0;
    }

    // 第二步:正向扫描找第一个不匹配的位置l
    int l = 0;
    while (l < n && long_word[l] == short_word[l]) {
        l++;
    }

    // 第三步:反向扫描找最后一个不匹配的位置r(r是最大的索引,使得long_word[r+1] != short_word[r])
    int r = n - 1;
    while (r >= 0 && long_word[r + 1] == short_word[r]) {
        r--;
    }

    // 第四步:判断有效删除位置的范围
    if (l > r) {
        // 所有从r+1到l的0-based位置都有效,对应1-based是(r+1)+1到l+1
        int count = l - r;
        printf("%d\n", count);
        for (int i = r + 1; i <= l; i++) {
            printf("%d ", i + 1);
        }
        printf("\n");
    } else {
        // 检查是否存在唯一有效位置:删除l后,long_word的剩余部分等于short_word
        bool valid = true;
        // 检查long_word[l+1 ... n] 是否等于 short_word[l ... n-1]
        for (int i = l; i < n; i++) {
            if (long_word[i + 1] != short_word[i]) {
                valid = false;
                break;
            }
        }
        if (valid) {
            printf("1\n%d\n", l + 1);
        } else {
            printf("0\n");
        }
    }

    return 0;
}

修正后的逻辑解释

  1. 输入处理:先判断两个单词的长度,确保长单词和短单词的正确性,长度差不为1直接输出0。
  2. 正向扫描:找到第一个不匹配的位置l,如果所有前n个字符都匹配,l会等于n
  3. 反向扫描:找到最后一个不匹配的位置r,如果所有反向对应位置都匹配,r会等于-1
  4. 有效位置判断
    • l > r:说明从r+1l的所有位置,删除后都能让长单词变成短单词,输出这些位置。
    • l <= r:只有删除l位置(1-based l+1)才可能有效,检查删除后的剩余部分是否完全匹配短单词,匹配则输出,否则输出0。

测试边界case

  • case1:长单词aaaaa,短单词aaaa → 输出5,然后1 2 3 4 5(正确)。
  • case2:长单词aabaaa,短单词abaaa → 输出2,然后1 2(正确)。
  • case3:输入顺序反转a aa → 自动交换为长单词aa,短单词a → 输出2,然后1 2(正确)。
  • case4:长单词abcdxxxef,短单词abcdxxef → 输出3,然后5 6 7(符合你的样例输出)。

内容来源于stack exchange

火山引擎 最新活动