如何在 LeetCode 中使用指针 C 中的两个求和问题

How to use pointers in LeetCode Two Sum problem in C

提问人:Leodero20 提问时间:8/16/2023 最后编辑:halferLeodero20 更新时间:9/5/2023 访问量:128

问:

我是 LeetCode 的新手,我唯一的 C 语言背景是它的一门基础知识。我希望改进和学习更多。我认为我在这里的问题出在指针或 malloc 上。我该如何解决这个问题?

这是我的代码:

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int *ans;
    ans = (int*)malloc(2*sizeof(int));
    *returnSize = 2;

    for(int i=0; i<numsSize; i++){
        for(int j=i++ ; j<numsSize; j++){
            if( nums[i] + nums[j] == target ){
                ans[0] = i;
                ans[1] = j;
                break;
            } 
        }
    }
    return *ans;
}

这是错误:

第 207 行:字符 3:运行时错误:加载类型“int”的地址0x000000000001未对齐,这需要 4 字节对齐 [Serializer.c] 0x000000000001:注意:指针指向此处

根据我对指针的理解:

  • *ans[0] = i应该将 i 的值(一个整数)分配给指针 ans[0] 指向的值。但是,这会产生错误“错误:一元'*'(有'int')的无效类型参数”。所以,我尝试了上面的代码。
  • 'return *ans' 应该返回数组 [i,j]?
c 函数 指针 malloc 嵌套循环

评论

4赞 Weather Vane 8/16/2023
该函数具有类型并且是相同的类型,因此您应该.int*ansreturn ans;
4赞 Weather Vane 8/16/2023
循环看起来很可疑。外层循环有两个增量。你是说吗?for(int j=i++ ; j<numsSize; j++)ifor(int j=i+1 ; j<numsSize; j++)
3赞 Tom Karzes 8/16/2023
首先要做的是修复您的警告。这些都是错误。您的函数被声明为返回 ,但您正在尝试返回 .更改为 Remember、has type 和 has type 。int *intreturn *ans;return ans;*ansintansint *
2赞 Weather Vane 8/16/2023
请注意,这只会破坏内部循环。根据问题要求,您可能希望只在那里,并在函数结束时向调用方指示不匹配。breakreturn arr;return NULL;target
2赞 Ian Abbott 8/16/2023
您可以将其更改为,因为已经找到了答案。如果在外部循环终止时没有找到答案,我不知道函数应该做什么,可能?break;return ans;free(ans);return NULL;

答:

4赞 Joel 8/16/2023 #1

如果你在 C 语言中有一个指针,你可以使用类似 的运算符取消引用它(获取它所指向的对象)。或者,如果为多个对象分配了内存(例如通过),则可以使用where代表要检索的对象的偏移量来访问每个对象。但是,如果为负数或大于/等于为其分配的内存量,则超出边界访问内存,这是未定义的行为,并可能导致分段错误。int* ptr**ptrmalloc()*(ptr + i)ii

由于写作有点丑陋且难以阅读,因此您可以使用它来代替,它做同样的事情。*(ptr + i)ptr[i]


*ans[0] = i应该分配 i 的值

您可以使用 or or 来获得工作结果。这三个选项都是一样的,但我更喜欢最后一个,因为你有一个数组,而不仅仅是你的指针指向的单个元素。(如果它只是一个数组,你应该使用它来使其更容易阅读和理解它不是一个数组。*ans = i*(ans + 0) = ians[0] = i*ans

return *ans应该返回数组 [i,j]

同样的问题又来了。当你像 一样取消引用它时,你不会返回整个数组,而只返回它指向的第一件事,即整数。相反,你应该.*ansireturn ans;

在内部循环中,您使用 ,它确实设置为 ,然后递增 1。这不是你想要的行为,因为它会跳过一个完整的迭代,这可能会导致你跳过你要查找的值。对于第一次迭代,并且 和 是相同的,但问题表明情况并非如此。所以你可以在你的内部循环中使用。forint j=i++jiiiijint j = i + 1for


代码的其余部分应该可以工作,但可以改进一点。我想你想在你的语句中退出你的两个循环? 只存在内部循环,这不会给你带来错误的结果,因为问题描述指出“只有一个有效的答案存在”,但你可以立即退出。否则,您可以使用一些额外的变量或跳转到函数的末尾。forbreakifbreakreturn ans;goto

而且你不会检查什么会返回你。如果它返回(尽管这可能不会发生),那么当您尝试取消引用时,您的程序将崩溃。malloc()NULLans


问题没有说如果你没有找到有效的一对会发生什么,但我认为“只有一个有效答案存在”意味着总有一个有效答案,不多也不少。对于我的解决方案,我假设我可能找不到一对,并且只有在我实际找到一对时才分配和设置为。ans*returnSize2

int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
    *returnSize = 0;

    for (int i = 0; i < numsSize; i++) {
        for (int j = i + 1; j < numsSize; j++) {
            if (nums[i] + nums[j] == target) {
                int* ans = malloc(2 * sizeof(int));
                if (ans != NULL) {
                    *returnSize = 2;
                    ans[0] = i;
                    ans[1] = j;
                }
                return ans;
            }
        }
    }

    return NULL;
}

我是 LeetCode 的新手,我唯一的 C 语言背景是它的一门基础知识。

我想我应该在这个答案中补充一点,LeetCode 可能很有趣,或者你认为它可以帮助您学习一门语言或帮助您在某个地方被录用,但这不是开始一门新语言的正确地方,也没有教你最佳实践。

在我看来,LeetCode 的目标是更深入地了解算法和数据结构,但你需要事先知道你正在使用的语言。如果你只知道一些基础知识,并且为第一个简单的问题而苦苦挣扎,我建议你在尝试解决一些 LeetCode 问题之前,先学习一些关于这门语言的知识。

3赞 Vlad from Moscow 8/16/2023 #2

该函数存在几个问题。

int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int *ans;
    ans = (int*)malloc(2*sizeof(int));
    *returnSize = 2;

    for(int i=0; i<numsSize; i++){
        for(int j=i++ ; j<numsSize; j++){
            if( nums[i] + nums[j] == target ){
                ans[0] = i;
                ans[1] = j;
                break;
            } 
        }
    }
    return *ans;
}

第一个是表达式具有类型,但返回类型是 。您需要返回一个指针,而不是 类型的对象。*ansintint *int

return ans;

注意表达式等价于表达式。*ansans[0]

第二个问题是在内部 for 循环中使用后缀递增运算符。由于这种增量,指针 wll 指向的数组的某些元素将被跳过,因为该变量在外部 for 循环中第二次递增。i++numsi

内部 for 循环中使用的语句仅中断内部 for 循环。break

该函数返回指向已分配的动态数组的指针

ans = (int*)malloc(2*sizeof(int));
*returnSize = 2;

但是,如果数组中找不到相等的元素,则函数的调用方将无法确定这一点。target

还要注意的是,教给糟糕的编程风格。至少该函数应声明为LeetCode

size_t * twoSum( const int *nums, size_t numsSize, int target );

第四个参数是冗余的。如果数组中没有两个元素等于 target,则该函数只能返回一个 null 指针。很明显,在没有参数的情况下,由于函数的任务,返回的指针可以指向两个元素的数组。returnSize

函数可以按以下方式定义

size_t * twoSum( const int *nums, size_t numsSize, int target )
{
    size_t *ans = NULL;

    if ( !( numsSize < 2 ) )
    {
        int found = 0;
        for ( size_t i = 0; !found && i < numsSize; i++ )
        {
            size_t j = i + 1;
            while ( j < numsSize && nums[i] + nums[j] != target ) ++j;

            if ( j != numsSize )
            {
                found = 1;
                ans = malloc( 2 * sizeof( *ans ) );
                if ( ans != NULL )
                {
                    nums[0] = i;
                    nums[1] = j;
                }
            }
        }
    }

    return ans;
}

在调用方中,你可以通过以下方式检查返回的指针是否不等于 NULL

size_t *ans = twoSum( nums, numsSize, target );

if ( ans != NULL )
{
    // do something with the returned indices in the dynamically allocated array
}

尽管返回两个成员的结构而不是动态分配的数组会更好。类似的东西

struct Pair 
{ 
    size_t first; 
    size_t second; 
};

在这种情况下,该函数可以如下所示

struct Pair twoSum( const int *nums, size_t numsSize, int target )
{
    struct Pair ans = { .first = 0, .second = 0 };

    if ( !( numsSize < 2 ) )
    {
        int found = 0;
        for ( size_t i = 0; !found && i < numsSize; i++ )
        {
            size_t j = i + 1;
            while ( j < numsSize && nums[i] + nums[j] != target ) ++j;

            if ( j != numsSize )
            {
                found = 1;
                ans.first  = i;
                ans.second = j;
            }
        }
    }

    return ans;
}

在来电者中,你可以写

struct Pair ans = twoSum( nums, numsSize, target );

if ( ans.first != ans.second )
{
    // do something with the returned indices
}