【问题标题】:Why is my solution for Super Reduced String(HackerRank) question working fine on my computer but giving wrong answers in HackerRank?为什么我的 Super Reduced String(HackerRank) 问题的解决方案在我的计算机上运行良好,但在 HackerRank 中给出错误答案?
【发布时间】:2020-06-26 22:02:17
【问题描述】:

当我在 Hackerrank 中运行我的代码时,它失败了 6/16 测试用例,但是当我在我的计算机上尝试相同的测试用例时它工作正常。

这是我在电脑上运行的代码:(我使用 Clion 作为 ide,最新的 MinGW 作为编译器。)

我使用在 HackerRank 上失败的测试用例之一初始化字符串。

#include <string.h>
#include <stdio.h>
//#include <stdlib.h>
char* superReducedString(char* s);
int contain(char *S,char find);
void copyWithout(char *S,char *T,char trash);
int countWithout(char *S,char trash);
int findSize(char *S);
void fillString(char *S,char filler);
int main(){
    char s[] = {"ppffccmmssnnhhbbmmggxxaaooeeqqeennffzzaaeeyyaaggggeessvvssggbbccnnrrjjxxuuzzbbjjrruuaaccaaoommkkkkxx"};
    char *result = superReducedString(s);
    printf("%s",result);
}
int findSize(char *S){
    int i = 0;
    while(*(S+i) != '\0'){
        i++;
    }
    return i;
}
void fillString(char *S,char filler){
    int i = 0;
    while(*(S+i) != '\0'){
        *(S+i) = filler;
        i++;
    }
}
void copyWithout(char *S,char *T,char trash){
    fillString(T,'0');
    int i = 0;
    int count = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) != trash){
            *(T+count) = *(S+i);
            count++;
        }
        i++;
    }
}
int countWithout(char *S,char trash){
    int i = 0;
    int count = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) != trash){
            count++;
        }
        i++;
    }
    return count;
}
int contain(char *S,char find){
    int i = 0;
    int flag = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) == find){
            flag = 1;
        }
        i++;
    }
    return flag;
}
char* superReducedString(char* s){
    static char empty[] = "Empty String";
    static char result[1024];
    int flag = 1;
    char temp[findSize(s)];
    fillString(temp,'0');
    int i,j;//Loop variable.
    i = 0;
    while(*(s + i) != '\0'){
        j = 0;
        //Checking if adjacent numbers is same. If it is changing them to '0'.
        while(s[j] != '\0') {
            if (s[j] == s[j + 1]) {
                *(s + j) = '0';
                *(s + j + 1) = '0';
            }
            j++;
        }
        if(contain(s,'0') == 0){ //If there is no zero in original string that means nothing changed.
            return s;
        }else{
            copyWithout(s,temp,'0');//If there are zeros in it, copy it to a temp char array without zeros.
        }
        strcpy(s,temp);//Copy temp to s again for swapping.
        i++;
    }
    int count = countWithout(s,'0'); //Calculate the size of original string without zeros.
    char finalString[count];//Initialize a new string with the calculated size.
    copyWithout(s,finalString,'0'); //Copy original string to finalString without zeros to obtain a clear zeroless string.
    strcpy(result,finalString);//copy finalstring to static result string to return it.
    i = 0;
    while(*(result+i) != '\0'){ //Check if result string consists of zeroes. If it is code will return empty string.
        if(*(result+i) != '0'){
            flag = 0;
        }
        i++;
    }
    if(flag == 0){
        return result;
    }else{
        return empty;
    }
}

这是我在 HackerRank 上运行的代码:

#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* superReducedString(char* s);
int contain(char *S,char find);
void copyWithout(char *S,char *T,char trash);
int countWithout(char *S,char trash);
int findSize(char *S);
void fillString(char *S,char filler);
char* readline();
int main()
{
    FILE* fptr = fopen(getenv("OUTPUT_PATH"), "w");

    char* s = readline();

    char* result = superReducedString(s);

    fprintf(fptr, "%s\n", result);

    fclose(fptr);

    return 0;
}

char* readline() {
    size_t alloc_length = 1024;
    size_t data_length = 0;
    char* data = malloc(alloc_length);

    while (true) {
        char* cursor = data + data_length;
        char* line = fgets(cursor, alloc_length - data_length, stdin);

        if (!line) {
            break;
        }

        data_length += strlen(cursor);

        if (data_length < alloc_length - 1 || data[data_length - 1] == '\n') {
            break;
        }

        alloc_length <<= 1;

        data = realloc(data, alloc_length);

        if (!data) {
            data = '\0';

            break;
        }
    }

    if (data[data_length - 1] == '\n') {
        data[data_length - 1] = '\0';

        data = realloc(data, data_length);

        if (!data) {
            data = '\0';
        }
    } else {
        data = realloc(data, data_length + 1);

        if (!data) {
            data = '\0';
        } else {
            data[data_length] = '\0';
        }
    }

    return data;
}
int findSize(char *S){
    int i = 0;
    while(*(S+i) != '\0'){
        i++;
    }
    return i;
}
void fillString(char *S,char filler){
    int i = 0;
    while(*(S+i) != '\0'){
        *(S+i) = filler;
        i++;
    }
}
void copyWithout(char *S,char *T,char trash){
    fillString(T,'0');
    int i = 0;
    int count = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) != trash){
            *(T+count) = *(S+i);
            count++;
        }
        i++;
    }
}
int countWithout(char *S,char trash){
    int i = 0;
    int count = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) != trash){
            count++;
        }
        i++;
    }
    return count;
}
int contain(char *S,char find){
    int i = 0;
    int flag = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) == find){
            flag = 1;
        }
        i++;
    }
    return flag;
}
char* superReducedString(char* s){
    static char empty[] = "Empty String";
    static char result[1024];
    int flag = 1;
    char temp[findSize(s)];
    fillString(temp,'0');
    int i,j,k;//Loop variable.
    i = 0;
    while(*(s + i) != '\0'){
        j = 0;
        while(s[j] != '\0') {
            if (s[j] == s[j + 1]) {
                *(s + j) = '0';
                *(s + j + 1) = '0';
            }
            j++;
        }
        if(contain(s,'0') == 0){
            return s;
        }else{
        //    printf("temp0 = %s s0 = %s\n",temp,s);
            copyWithout(s,temp,'0');
        //    printf("temp1 = %s s1 = %s\n",temp,s);
        }
        //printf("%s\n",temp);
        strcpy(s,temp);
        i++;
    }
    int count = countWithout(s,'0');
    char finalString[count];
    copyWithout(s,finalString,'0');
    strcpy(result,finalString);
    i = 0;
    while(*(result+i) != '\0'){
        if(*(result+i) != '0'){
            flag = 0;
        }
        i++;
    }
    if(flag == 0){
        return result;
    }else{
        return empty;
    }
}

唯一的区别是 main 函数和 HackerRank 用于获取输入的函数。

我不知道这是否有帮助,但有时我的代码可能会针对相同的输入给出错误的答案。 我的意思是:

输入 = "acdqglrfkqyuqfjkxyqvnrtysfrzrmzlygfveulqfpdbhlqdqrrqdqlhbdpfqluevfgylzmrzrfsytrnvqyxkjfquyqkfrlacdqj"

虽然它应该给出“acdqgacdqj”作为答案,但它给出了“acdqgacdqjÑ” 最后一个字符随机变化。

但是对于其他输入,无论我运行多少次,它都会在我的计算机上给出正确的答案。

【问题讨论】:

  • char temp[findSize(s)]; fillString(temp,'0'); 无效。 temp 不是以零结尾的。 *(s + j + 1) = '0'; 可能越界。另外我认为您的findSize 没有为零终止字符考虑空间。
  • @KamilCuk 请您再解释一下好吗?我没明白你的意思。
  • char temp[findSize(s)]; 未初始化。在fillString 中,您迭代直到temp[i] != '\0'temp 数组的内容没有初始化,你不能指望它有零字节。 char finalString[count]; copyWithout(s,finalString,'0'); strcpy(result,finalString); 访问越界 - 您没有复制零终止字符,因此 strcpy 访问数组越界,这很可能是您要查找的错误。
  • @KamilCuk 你是对的。我为犯这么简单的错误感到尴尬。您能否将您的评论转换为答案,以便我将问题标记为已解决?
  • 函数:findSize() 可以替换为对strlen()的调用

标签: c string char


【解决方案1】:
  • char temp[findSize(s)]; fillString(temp,'0'); 无效。在fillString 中迭代直到元素等于'\0'temp 未初始化 - 你不能期望它有任何特定的值(甚至读取未初始化的值也是未定义的行为)。
  • char finalString[count]; count 中太小 - 它不考虑零终止字符。 copyWithout(s,finalString,'0'); 没有复制零终止字符。这会导致 strcpy(result,finalString); 在搜索....时访问数组越界。零终止字符。

使用 C 字符串时,您通常会在代码中的任何地方看到一个神奇的 + 1

建议:

  • 最好不要使用可变长度数组(大小表达式不是常量表达式的数组)。更喜欢使用动态分配。
  • findSize 只是 strlen...
  • fillString 只是 memset(string, value, strlen(string));
  • 使用编译器时,请始终启用所有选项。当使用gcc 时,您可以使用gcc -g -Wall -Wextra -fsanitize=address sourcefile.c - sanitize 将允许非常快速地找到堆栈变量上的所有越界访问。使用valgrind 查找动态分配泄漏。
  • 我建议将copyWithout 中的参数顺序更改为(destination, source, fill),因此它与strcpy(destination, source) 相同 - 即。目的地是第一位的。

似乎将部分代码修复为:

char* superReducedString(char* s){
    ...
    // char temp[findSize(s)];
    char temp[findSize(s) + 1];
    // fillString(temp,'0');
    memset(temp, '0', findSize(s));
    temp[findSize(s)] = '\0';
    ...
    char finalString[count + 1];//Initialize a new string with the calculated size.
    memset(finalString, '0', count);
    finalString[count] = '\0';
}

足以让我-fsanitize 停止出错。

【讨论】:

    【解决方案2】:

    我不知道你的错误到底在哪里,但从输出中很清楚你正在使用未初始化的内存。而在您的计算机上,未初始化的内存中包含零纯属巧合,而在用于测试的计算机上则没有。

    一般来说,如果您遇到问题“它在计算机 A 上有效,但在计算机 B 上无效”,那么您的代码中的未定义行为通常就是答案,这里最类似于未初始化的内存。

    【讨论】:

      猜你喜欢
      • 2022-04-15
      • 1970-01-01
      • 1970-01-01
      • 2020-05-14
      • 1970-01-01
      • 2021-06-05
      • 1970-01-01
      • 1970-01-01
      • 2017-10-16
      相关资源
      最近更新 更多