三数之和——貌似是内存分配和数组索引问题

RichAndMerry 2020-01-08 05:16:50
题目:给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
弄了一下午,也弄不好这个bug。这样动态的数组,在C里面不知道要怎么分配合适。
报错信息:
Line 37: Char 27: runtime error: store to address 0x626000002fe0 with insufficient space for an object of type 'int *' (solution.c)
0x626000002fe0: note: pointer points here
20 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
^

void quickSort(int* nums, int left, int right);
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){

if(numsSize < 3)
{
*returnSize = 0;
return NULL;
}
int **re = (int**)malloc(sizeof(int*) * 1500); //Line2222;
*returnColumnSizes = (int*)malloc(sizeof(int) * 1500); //Line3333
quickSort(nums, 0, numsSize - 1);
int geshu = 0;
for(int i = 0; i < numsSize - 2 && nums[i] <= 0 && geshu < INT_MAX; i++)
{
if(i > 0 && nums[i] == nums[i-1])
continue;
for(int j = i + 1, k = numsSize - 1; j < k && nums[k] >= 0;)
{
if(j > 0 && nums[j] == nums[j - 1])
{
j++;
continue;
}
if(k < numsSize - 1 && nums[k] == nums[k + 1])
{
k--;
continue;
}
long temp = nums[i] + nums[j] + nums[k];
if(temp == 0)
{
re[geshu] = (int*)malloc(sizeof(int) * 3); //Line 37 这里报错。
re[geshu][0] = nums[i];
re[geshu][1] = nums[j];
re[geshu][2] = nums[k];
(*returnColumnSizes)[geshu] = 3;
geshu++;
}
else if(temp > 0)
{
k--;
}
else
{
j++;
}
}
}
* returnSize = geshu;
return re;
}
void quickSort(int* nums, int left, int right)
{
if(left >= right)
return;
int i = left, j = right, key = nums[left];
while(i < j)
{
while(i < j && nums[j] >= key)
j--;
nums[i] = nums[j];
while(i < j && nums[i] <= key)
i++;
nums[j] = nums[i];
}
nums[i] = key;
quickSort(nums, 0, i - 1);
quickSort(nums, i + 1, right);
}
...全文
256 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
zerozerg2006 2020-01-13
  • 打赏
  • 举报
回复
引用 9 楼 Stranger_Green 的回复:
[quote=引用 8 楼 u013962723 的回复:] 大兄弟,你觉得这个算法的瓶颈是在排序上???
你有更好的算法?除去排序不谈,这已经是我找到的省时的方法了。 两个for处理。虽然里面还有两个while,但那也是为了去重,也是为了减少外面循环的次数。[/quote] 赌5毛,你传一个有序数列进去,把排序删掉一样超时 你可以自己想一下你核心算法的复杂度是多少,快排的复杂度是多少
RichAndMerry 2020-01-10
  • 打赏
  • 举报
回复
引用 10 楼 遇见女神 的回复:
1)排序可以用c语言提供的qsort函数;
2)去重不用while循环并且先去重再下一步骤,参考你自己的代码if(XXX)continue;
后来是用的qsort过的超时。
去重开始是计划把j和k的两个for放在前面的。但是后来考虑到,如果有三个或以上连续的0,0, 0,会将这组结果排除掉。
所以后来改为在确认了一组数据后,排除相同的数。这样逻辑比较直观,也不会把可能的数据除掉。
zerozerg2006 2020-01-09
  • 打赏
  • 举报
回复
大兄弟,你觉得这个算法的瓶颈是在排序上???
遇见女神 2020-01-09
  • 打赏
  • 举报
回复
1)排序可以用c语言提供的qsort函数; 2)去重不用while循环并且先去重再下一步骤,参考你自己的代码if(XXX)continue;
RichAndMerry 2020-01-09
  • 打赏
  • 举报
回复
引用 8 楼 u013962723 的回复:
大兄弟,你觉得这个算法的瓶颈是在排序上???
你有更好的算法?除去排序不谈,这已经是我找到的省时的方法了。
两个for处理。虽然里面还有两个while,但那也是为了去重,也是为了减少外面循环的次数。
RichAndMerry 2020-01-09
  • 打赏
  • 举报
回复
自己找到这个问题了,temp == 0后,赋值结束后,没有对j++和k--,以至于陷在循环里了。
但是代码改好后,竟然还是超时。郁闷啊,快排不够快吗?
void quickSort(int* nums, int left, int right);
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){

if(numsSize < 3)
{
*returnSize = 0;
return NULL;
}
int **re = (int**)malloc(sizeof(int*) * numsSize * 2);
*returnColumnSizes = (int*)malloc(sizeof(int) * numsSize * 2);
quickSort(nums, 0, numsSize - 1);
int geshu = 0;
for(int i = 0; i < numsSize - 2 && nums[i] <= 0; i++)
{
if(i > 0 && nums[i] == nums[i-1])
continue;
for(int j = i + 1, k = numsSize - 1; j < k && nums[k] >= 0;)
{
long temp = nums[i] + nums[j] + nums[k];
if(temp == 0)
{
re[geshu] = (int*)malloc(sizeof(int) * 3);
re[geshu][0] = nums[i];
re[geshu][1] = nums[j];
re[geshu][2] = nums[k];
(*returnColumnSizes)[geshu++] = 3;
while(j < k && nums[j] == nums[j + 1])
j++;
while(j < k && nums[k] == nums[k - 1])
k--;
j++;
k--;
}
else if(temp > 0)
{
k--;
}
else
{
j++;
}
}
}
* returnSize = geshu;
return re;
}
void quickSort(int* nums, int left, int right)
{
if(left >= right)
return;
int i = left, j = right, key = nums[left];
while(i < j)
{
while(i < j && nums[j] >= key)
j--;
nums[i] = nums[j];
while(i < j && nums[i] <= key)
i++;
nums[j] = nums[i];
}
nums[i] = key;
quickSort(nums, 0, i - 1);
quickSort(nums, i + 1, right);
}
RichAndMerry 2020-01-08
  • 打赏
  • 举报
回复
引用 4 楼 gouyanfen 的回复:
[quote=引用 3 楼 Stranger_Green 的回复:]
[quote=引用 2 楼 gouyanfen 的回复:]
int **re = (int**)malloc(sizeof(int*) * 1500); 这个是个什么操作?分配返回的是指针,你强转为二级指针他的值还是指向分配空间的一个指针地址
re存了一个地址A,A地址中存了一个指针B,这个操作是让B=分配的地址
你的固定是返回三个数字的, 直接分配 单个空间*3*总数量的一维来解决,
struct num_struct
{int num1;
int num2;
int num3;
}
num_struct * re=malloc(sizeof(num_struct)*1500;
XX XX XX XX XX XX
| | | |
________ ________
re[0] re[1]

二维数组一直都是那样分配内存的。1500那个,是因为事先不知道这个数组geshu多少行。只好先定一个一个大点儿的值。
re[geshu] = (int*)malloc(sizeof(int) * 3); 是为每一行re[geshu]的大小分配,确定是三个数字。re[geshu][0],re[geshu][1], re[geshu][2]。
如果按照你说的,只在第一次为re分配内存。每行不单独分配时,运行到下方re[geshu][0] 时,会报错的。[/quote]
只要你分配的够的话,怎么会出错呢,调用改一下re[geshu]->num1;
你目前的是
地址一->指针->指向三个数的地址
地址二->指针->指向三个数的地址
...
地址N->指针->指向三个数的地址
数组加动态
你不确定的话就用结构体链表来解决动态的问题,需要一个就分配一个。[/quote]题目给的要求是,返回二维数组。并且要给出二维数组大小。
问题就是,我现在测试输入的nums,只是包含五个数的数组,上面的分配,肯定不会不够啊。但不知道为啥就是一直报错。找了一下午都没搞定。
gouyanfen 2020-01-08
  • 打赏
  • 举报
回复
引用 3 楼 Stranger_Green 的回复:
[quote=引用 2 楼 gouyanfen 的回复:] int **re = (int**)malloc(sizeof(int*) * 1500); 这个是个什么操作?分配返回的是指针,你强转为二级指针他的值还是指向分配空间的一个指针地址 re存了一个地址A,A地址中存了一个指针B,这个操作是让B=分配的地址 你的固定是返回三个数字的, 直接分配 单个空间*3*总数量的一维来解决, struct num_struct {int num1; int num2; int num3; } num_struct * re=malloc(sizeof(num_struct)*1500; XX XX XX XX XX XX | | | | ________ ________ re[0] re[1]
二维数组一直都是那样分配内存的。1500那个,是因为事先不知道这个数组geshu多少行。只好先定一个一个大点儿的值。 re[geshu] = (int*)malloc(sizeof(int) * 3); 是为每一行re[geshu]的大小分配,确定是三个数字。re[geshu][0],re[geshu][1], re[geshu][2]。 如果按照你说的,只在第一次为re分配内存。每行不单独分配时,运行到下方re[geshu][0] 时,会报错的。[/quote] 只要你分配的够的话,怎么会出错呢,调用改一下re[geshu]->num1; 你目前的是 地址一->指针->指向三个数的地址 地址二->指针->指向三个数的地址 ... 地址N->指针->指向三个数的地址 数组加动态 你不确定的话就用结构体链表来解决动态的问题,需要一个就分配一个。
RichAndMerry 2020-01-08
  • 打赏
  • 举报
回复
引用 2 楼 gouyanfen 的回复:
int **re = (int**)malloc(sizeof(int*) * 1500); 这个是个什么操作?分配返回的是指针,你强转为二级指针他的值还是指向分配空间的一个指针地址
re存了一个地址A,A地址中存了一个指针B,这个操作是让B=分配的地址
你的固定是返回三个数字的, 直接分配 单个空间*3*总数量的一维来解决,
struct num_struct
{int num1;
int num2;
int num3;
}
num_struct * re=malloc(sizeof(num_struct)*1500;
XX XX XX XX XX XX
| | | |
________ ________
re[0] re[1]

二维数组一直都是那样分配内存的。1500那个,是因为事先不知道这个数组geshu多少行。只好先定一个一个大点儿的值。
re[geshu] = (int*)malloc(sizeof(int) * 3); 是为每一行re[geshu]的大小分配,确定是三个数字。re[geshu][0],re[geshu][1], re[geshu][2]。
如果按照你说的,只在第一次为re分配内存。每行不单独分配时,运行到下方re[geshu][0] 时,会报错的。
gouyanfen 2020-01-08
  • 打赏
  • 举报
回复
int **re = (int**)malloc(sizeof(int*) * 1500); 这个是个什么操作?分配返回的是指针,你强转为二级指针他的值还是指向分配空间的一个指针地址 re存了一个地址A,A地址中存了一个指针B,这个操作是让B=分配的地址 你的固定是返回三个数字的, 直接分配 单个空间*3*总数量的一维来解决, struct num_struct {int num1; int num2; int num3; } num_struct * re=malloc(sizeof(num_struct)*1500; XX XX XX XX XX XX | | | | ________ ________ re[0] re[1]
RichAndMerry 2020-01-08
  • 打赏
  • 举报
回复
如果把Line222和Line333处改为:
int **re = (int**)malloc(sizeof(int*) * (numsSize + 1) * 6);
*returnColumnSizes = (int*)malloc(sizeof(int) * (numsSize + 1) * 6);

报错信息就是:
=================================================================
==29==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x613000000190 at pc 0x00000040251a bp 0x7ffc37c0d980 sp 0x7ffc37c0d978
WRITE of size 8 at 0x613000000190 thread T0
#2 0x7f4b2a50c2e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)
0x613000000190 is located 0 bytes to the right of 336-byte region [0x613000000040,0x613000000190)
allocated by thread T0 here:
#0 0x7f4b2bdbb2b0 in malloc (/usr/local/lib64/libasan.so.5+0xe82b0)
#3 0x7f4b2a50c2e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)
Shadow bytes around the buggy address:
0x0c267fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c267fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c267fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x0c267fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c267fff8020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c267fff8030: 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==29==ABORTING

69,370

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧