LEETCODE学习 -- 2.两数之和

题目-两数之和

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers

方法 模拟竖式运算

思路较为清晰,两个链表相加,数位顺序是大尾端,也就是从链表的头开始进行加法运算即可,进位用一个int型变量作为缓存,等到进入下一个循环中加入到求和中即可。

此处对链表的遍历有两个问题:

  1. 不知道l1与l2哪个较长
  2. 提前设定好输出链表的大小会带来内存溢出问题

问题1的解决,我们采用 while(p!=NULL||q!=NULL) 的写法,这样可以一直遍历到最长链表的尾部,并且在进行链表向下转移的判断条件是 p->next != NULL

问题2的解决,采用遍历链表的同时分配新的内存空间。在每个循环内部,使用 cur->next = (struct ListNode*)malloc(sizeof(struct ListNode)) 的写法。

另外需要注意的是,会出现最后生成的链表长度大于原先任一链表的情况,此时需要考虑最后一个结点的处理逻辑。
Note: The returned array must be malloced, assume caller calls free().

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
    int x, y, num, flag=0;
    struct ListNode *p = l1, *q = l2;
    struct ListNode *cur = (struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode *pre_cur ;
    cur->next = NULL;
    struct ListNode *head = cur;
    while(p!=NULL || q!=NULL)
    {
        x = (p!=NULL) ? p->val : 0;
        y = (q!=NULL) ? q->val : 0;
        num = x+y+flag;
        flag = num/10;
        cur->val = num%10;
        cur->next = (struct ListNode*)malloc(sizeof(struct ListNode));
        pre_cur = cur;
        cur = cur->next;
        cur->next = NULL;
        if(p!=NULL)
            p = p->next;
        if(q!=NULL)
            q = q->next;
    }
    if(flag > 0)
    {      
        cur->val = 1;
        cur->next = NULL;
    }
    else 
    {
        cur = pre_cur;
        cur->next = NULL;
    }
    return head;
}


方法二 hash查找

方法一的复杂度在于,要想得知外层循环当前所在的数字是否为满足和要求的数字,需要将其后的所有数字都查询一遍,复杂度为O(n^2)。引入哈希表的思路是可以直接找到需要的数字是否在数组中,可以将复杂度降至O(n)。

哈希表的构建:

  1. 将hash[MAX_SIZE]的每一项初始化为-1
  2. 对nums数组进行遍历,假设当前对象为nums[i]
  3. 查看hash[nums[i]],如果该项的值为-1,就将其替换为i

例:
nums数组:[2 , 4 , 6 , 7]
nums下标: 0 1 2 3

hash表:[ -1,-1,0, -1, 1,-1, 2, 3,…]
hash下标:0 1 2 3 4 5 6 7

由此得到的hash表,可以作为第二个和因子的查询表。这样在外层循环当前指向nums[i]时,只需要查找hash[target - nums[i]]的值,如果为-1说明target - nums[i]在数组中不存在,如果为自然数则为target - nums[i]在数组中的位置。

另外需要注意的是,可能会出现负数,对于负数的操作则补充到hash表的队尾。

int *twoSum(int *nums, int numsSize, int target, int *returnSize)
{
    int i, hash[2048], *res = (int *)malloc(sizeof(int) * 2);
    memset(hash, -1, sizeof(hash));
    for (i = 0; i < numsSize; i++)
    {
        if (hash[(target - nums[i] + 2048) % 2048] != -1)
        {
            res[0] = hash[(target - nums[i] + 2048) % 2048];
            res[1] = i;
            *returnSize = 2;
            return res;
        }
        hash[(nums[i] + 2048) % 2048] = i;  
    }
    free(hash);
    *returnSize = 0;
    return res;
}

该算法要求hash表的大小需要足够大,不能发生正数区和负数区的碰撞。
通过在hash表中增加一项标记,标明每个项目入表时是正值还是负值可以解决一部分问题。

参考

https://leetcode-cn.com/problems/two-sum/solution/cyu-yan-ji-yu-shu-zu-de-san-lie-15xing-dai-ma-8ms-/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Therock_of_lty

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值