我是靠谱客的博主 纯真跳跳糖,最近开发中收集的这篇文章主要介绍LeetCode 1、两数之和(C)题目:1、两数之和题解 其他,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述


        作者只是一个小白,最近希望能提升自己的代码水平,所以开始刷leetcode。写博客是为了整理自己的学习内容,难免会出错。如果有大大发现,非常欢迎指正哦!


目录

题目:1、两数之和

题解

方法一:双重for循环,暴力枚举

1、自己的代码

2、代码一

方法二:哈希表

第一次检测

第一次存储

第二次检测

第二次存储

第三次检测

第三次存储

第四次检测

 其他

1、为什么给htable分配的是256个hnode的空间?

2、红框中的temp为什么不用先分配空间呢?


题目:1、两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] ==9 ,返回 [0, 1] 。


题解

方法一:双重for循环,暴力枚举

        这个思路比较简单,就不赘述,直接上代码了。 

1、自己的代码

        执行用时:96ms

        排名:超过32%提交记录

/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
int i,j;
for(i=0;i<numsSize;++i)
{
for(j=i+1;j<numsSize;++j)
{
if(nums[i]+nums[j]==target)
{
int* ret=(int*)malloc(sizeof(int)*2);
ret[0]=i,ret[1]=j;
*returnSize=2;
return ret;
}
}
}
*returnSize=0;
return NULL;
}

2、代码一

        执行用时:60ms

        排名:超过85%提交记录

/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
int a,b=0;
int* ret = malloc(sizeof(int) * 2);
for(int i=0;i<numsSize-1;++i){
int m=target-nums[i];
for(int j=i+1;j<numsSize;++j){
if(nums[j]==m){
ret[0]=i;
ret[1]=j;
*returnSize=2;
return ret;
}
}
}
*returnSize=0;
return NULL;
}

        60ms的是暴力解法中最快的。那我差在哪里呢?

        很明显,我在循环里堆了很多不必要的东西。如果把分配空间这一句放到外面,时间马上降到76ms;再把两数之和的运算放在第二重循环外,时间就降到68ms。代码如下:

        执行用时:68ms

        排名:超过83.5%提交记录

/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
int i,j;
int* ret=(int*)malloc(sizeof(int)*2);
for(i=0;i<numsSize;++i)
{
int m=target-nums[i];
for(j=i+1;j<numsSize;++j)
{
if(nums[j]==m)
{
ret[0]=i,ret[1]=j;
*returnSize=2;
return ret;
}
}
}
*returnSize=0;
return NULL;
}

        这时候我很奇怪,因为我觉得这时的代码应该和代码一是一样的了,可为什么会慢8ms呢?于是我用代码一测了几次,时间都是64ms或者68ms。所以可能是测试的例子变了吧。

方法二:哈希表

具体​​​​​​​哈希表的介绍可以查看这篇博客:数据结构 Hash表

        我个人的理解是将一串数据存储到哈希表,每一个数据至少需要有两个属性:index和val。index代表数据存储在表中的位置,是根据数据本身的值val通过一定的方式计算出来的,所以如果知道数据的值,就可以直接得到数据存储的位置,而不用一个一个去找,时间复杂度就从oleft ( n right )降到oleft ( 1 right )

        以下是大佬用哈希表写的代码:

        执行用时:0ms

        排名:超过100%提交记录

/**
* Note: The returned array must be malloced, assume caller calls free().
*/
struct hnode
{
int val;
int index;
struct hnode *next;
};
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
struct hnode **htable, *temp;
int key, index, sum;
int *result;
htable = malloc(256 * sizeof(struct hnode*));
memset(htable, 0, 256 * sizeof(struct hnode*));
result = (int*)malloc(2 * sizeof(int));
result[0] = 0;
result[1] = 0;
*returnSize = 2;
for (index = 0; index < numsSize; index++)
{
sum = target - nums[index];//我们的目标就是要找到sum这个值存在哪里
key = sum & 0xff;//sum这个值要存储也是存储在htable中key这个位置
temp = htable[key];//temp取出htable[key]中的内容
while (temp != NULL)//如果temp中有内容,因为可能存在数据冲突,仍要继续检查存储的数据的值是我们需要的,而不能直接返回结果
{
if (temp->val == sum)//是我们的需要的,则返回结果
{
result[0] = temp->index;
result[1] = index;
return result;
}
else
{
temp = temp->next;//如果不是我们需要的,就找该位置存储的其他数据
}
}
key = nums[index] & 0xff;//此处往下6行是将没有找到匹配成功的数据存入htable中
temp = malloc(sizeof(struct hnode));
temp->val = nums[index];
temp->index = index;
temp->next = htable[key];//这是将表中之前该位置存储的数据取出来,方便我们下一句将该位置的数据连同这一次的数据,整体存入htable中
htable[key] = temp;
}
return result;
}

         C中已经有写好uthash.h的头文件,我们可以很方便地直接构建哈希表。有需要的大家可以去github下载:uthash.h

        但这块代码没有用uthash.h,而是自己构建了一个哈希表。让我们来看看吧!

struct hnode
{
int val;
int index;
struct hnode *next;
};

        hnode就是一张存放数据的表格,val是存放数据的值,index是代表数据存储的位置,而next相当于在发生冲突的时候,多一块空间存储发生冲突的数据。

key = sum & 0xff;

        而这边计算存储位置的方法是取数据的二进制的后8位。

        要理解代码,最好是举个例子看看。为了能实现哈希表中数据存储冲突,方便选取数据,所以我代码里把0xff改成0xf,即只取数据二进制的后4位。

        nums = [2,18,34,7],target = 9

第一次检测

index = 0,key = 7,sum = 7

temp为空,所以直接跳过while循环。

​​​​​​​

第一次存储

key = 2,temp->val = 2,temp->index = 0,temp->next = NULL

htable[2]->val = 2,htable[2]->index = 0,htable[2]->next = NULL

第二次检测

index = 1,key = 7,sum = -9

temp为空,所以直接跳过while循环。

第二次存储

key = 2,temp->val = 18,temp->index = 1,temp->next.val = 2,temp->next.index = 0(第一次存储的数据)

(我不知道temp->next.val这种表达方式对不对,如果有大大知道,欢迎教教我)

htable[2]->val = 18,htable[2]->index = 1,htable[2]​​​​​​​->next.val = 2,htable[2]->next.index = 0(第一次存储的数据)​​​​​​​

第三次检测

index = 2,key = 7,sum = -25

temp为空,所以直接跳过while循环。

第三次存储

key = 3,temp->val = 34,temp->index = 2,temp->next.val = 18,temp->next.index = 1(第二次存储的数据),temp->next ->next.val = 2,temp->next->next.index = 0(第一次存储的数据)

​​​​​​​htable[2]->val = 34,htable[2]->index = 2,htable[2]->next.val = 18,htable[2]->next.index = 1(第二次存储的数据),htable[2]​​​​->next->next.val = 2,htable[2]->next->next.index = 0(第一次存储的数据)​​​​​​​

第四次检测

index = 3,key = 2,sum = 2

temp取得htable[2]中的内容,不为空,进入while循环。temp->val = 34,temp->index = 2(即第三次存储的数据)

因为temp->val = 34,sum = 2,所以temp->val != sum,所以执行temp = temp->next这一语句。

此时temp->val = 18, temp->index = 1(即第二次存储的数据) 

temp不为空,进入while循环。

同样因为temp->val != sum,所以执行temp = temp->next语句。

temp->val = 2,temp->index = 0(即第一次存储的数据) 

因为temp->val == sum,所以返回result,程序结束。

 其他

1、为什么给htable分配的是256个hnode的空间?


htable = malloc(256 * sizeof(struct hnode*));
memset(htable, 0, 256 * sizeof(struct hnode*));

因为这边计算数据存储位置的方法是:

key = sum & 0xff;

相当于取数据后8位,那么key的数量最多就是2^{8}=256个,所以分配256个hnode的空间就够了。

另外memset的作用是给htable赋值,在这边的作用是初始化为0。具体用法可以参考:memset()函数及其作用

另外,如果memset这句不写的话,在vscode里跑不会出问题,但在leetcode中会报错

Line 31: Char 21: runtime error: member access within misaligned address 0xbebebebebebebebe for type 'struct hnode', which requires 8 byte alignment [solution.c] 0xbebebebebebebebe: note: pointer points here <memory cannot be printed>

这一点我还没有想明白...

2、红框中的temp为什么不用先分配空间呢?

  为什么红框中temp之前没有分配空间操作,像malloc什么的,就可以直接进行赋值,而蓝框处temp之前已经赋过值了,还要分配空间呢?

最后

以上就是纯真跳跳糖为你收集整理的LeetCode 1、两数之和(C)题目:1、两数之和题解 其他的全部内容,希望文章能够帮你解决LeetCode 1、两数之和(C)题目:1、两数之和题解 其他所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部