力扣(LeetCode)刷题
【力扣】1、两数之和
【力扣】2、两数相加
前言
最近疫情又开始严重了起来,宅在家里太无聊了,闲着也是闲着,刷刷力扣玩。由于是练习算法,所以我更倾向于用C语言来实现,我对C语言的用法还停留在大学,如果有哪里写的不对的地方也欢迎各位小伙伴提出
一、题目
码云
来源:力扣(LeetCode)
先来看下题目
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
二、题解
这个题目在力扣上翻了几下,好像没有多个解法,这里就列出我做题过程中的两种解法吧,不过有一种解法拿去运行溢出了,也不太算 (╥╯^╰╥),这边也列举下吧
在做题前边先准备下一个链表,先定义一个list.h头文件,代码如下:
#ifndef ADD_TWO_NUMBERS_LIST_H
#define ADD_TWO_NUMBERS_LIST_H
typedef struct node {
int num;
struct node *next;
struct node *prev;
} Node;
typedef struct list {
int size;
Node *header;
Node *tail;
int (*add)(struct list *list, int num);
void (*clear)(struct list *list);
Node *(*get)(struct list *list, int index);
int (*length)(struct list *list);
} List;
int add(List *list, int num);
void clear(List *list);
Node *get(List *list, int index);
int length(List *list);
void printList(List *list);
List *create();
#endif
在定义一个list.c具体实现,代码如下:
#include <stdlib.h>
#include <stdio.h>
#include "list.h"
List *create() {
List *list = (List *) malloc(sizeof(List));
list->header = NULL;
list->tail = NULL;
list->length = length;
list->add = add;
list->clear = clear;
list->get = get;
list->size = 0;
return list;
}
int add(List *list, int num) {
if (list != NULL) {
Node *newNode = (Node *) malloc(sizeof(Node));
newNode->num = num;
newNode->next = NULL;
if (list->header == NULL) {
list->header = newNode;
list->tail = newNode;
newNode->prev = NULL;
list->size = 1;
} else {
Node *temp = list->tail;
newNode->prev = temp;
temp->next = newNode;
list->tail = newNode;
list->size++;
}
return 1;
}
return 0;
}
void clear(List *list) {
if (list != NULL) {
Node *node = list->header;
Node *temp = node;
while (node != NULL) {
temp = node->next;
free(node);
node = temp;
}
node = NULL;
temp = NULL;
free(list);
list = NULL;
}
}
int length(List *list) {
if (list != NULL) {
return list->size;
}
return -1;
}
Node *get(List *list, int index) {
if (list != NULL) {
if (index < list->size && index >= 0) {
Node *temp;
/**
* 下标在链表右侧,从尾指针开始查找
*/
if (index > (list->size / 2)) {
temp = list->tail;
for (int i = 0; i < list->size - index - 1; ++i) {
temp = temp->prev;
}
} else {
/**
* 下标在链表左侧,从头指针开始查找
*/
temp = list->header;
for (int i = 0; i < index; i++) {
temp = temp->next;
}
}
return temp;
}
}
return NULL;
}
void printList(List *list) {
if (list != NULL && list->size != 0) {
printf("list:");
for (int i = 0; i < list->length(list) - 1; ++i) {
printf("%d -> ", list->get(list, i)->num);
}
printf("%d\n", list->get(list, list->size - 1)->num);
} else {
printf("empty list\n");
}
}
定义好链表之后,再来看下解法,注:这里的链表结构和力扣上的不太一样,放上去执行的话需要转换一下才行。如下:
1.转换数字相加
对于这道题目,其实原先我想法是,转成数字进行相加,在转换成链表的,在自己机子上运行成功后,满心欢喜的拿到力扣上执行,结果。。计算量太大溢出了,所以这个解法算是失败的解法,这里一并放上来吧
本地机子上的代码,如下:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
#include <math.h>
__int128_t getRealNum(Node *node, int index) {
if (node != NULL) {
__int128_t powNum = 1;
for (int i = 1; i <= index; i++) {
powNum *= 10;
}
return node->num * powNum;
}
return 0;
}
List *addTwoNumbers(Node *l1, Node *l2) {
__int128_t sum = 0;
Node *t1 = l1;
Node *t2 = l2;
int index = 0;
while (t1 != NULL || t2 != NULL) {
sum += getRealNum(t1, index);
sum += getRealNum(t2, index);
index++;
if (t1 != NULL) {
t1 = t1->next;
}
if (t2 != NULL) {
t2 = t2->next;
}
}
List *list = create();
do {
list->add(list, sum % 10);
sum /= 10;
} while (sum != 0);
return list;
力扣上的代码,如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2);
__int128_t getRealNum(struct ListNode*node, int index);
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
__int128_t sum = 0;
struct ListNode *t1 = l1;
struct ListNode *t2 = l2;
int index = 0;
while (t1 != NULL || t2 != NULL) {
sum += getRealNum(t1, index);
sum += getRealNum(t2, index);
index++;
if (t1 != NULL) {
t1 = t1->next;
}
if (t2 != NULL) {
t2 = t2->next;
}
}
struct ListNode* list = (struct ListNode*)malloc(sizeof(struct ListNode));
list->next = NULL;
struct ListNode* temp= list;
while (true) {
temp->val = sum % 10;
sum /= 10;
if(sum ==0){
break;
}
struct ListNode* next = (struct ListNode*)malloc(sizeof(struct ListNode));
next->next=NULL;
temp->next=next;
temp = temp->next;
}
return list;
}
__int128_t getRealNum(struct ListNode *node, int index) {
if (node != NULL) {
__int128_t powNum = 1;
for (int i = 1; i <= index; i++) {
powNum *= 10;
}
return node->val * powNum;
}
return 0;
}
执行到这里,溢出了,位数实在太大了,如下:
看到这里我就放弃,再继续往下计算,就算能通过,耗时也会很长的
2.同一位置相加
这个解法就是官方的解法了,就是把链表的同一位置的数字相加即可,这里需要注意的有两点:一是长度不同的链表,短的需要补0,二是需要注意下进位
本地机子上的代码,如下:
int addNum(Node *n1, Node *n2, int *sum, int carry) {
int num1 = 0;
int num2 = 0;
if (n1 != NULL) {
num1 = n1->num;
}
if (n2 != NULL) {
num2 = n2->num;
}
*sum = num1 + num2 + carry;
return *sum >= 10 ? 1 : 0;
}
List *addTwoNumbers(Node *l1, Node *l2) {
int *sum = (int *) malloc(sizeof(int));
Node *t1 = l1;
Node *t2 = l2;
int carry = 0;
List *list = create();
while (t1 != NULL || t2 != NULL) {
carry = addNum(t1, t2, sum, carry);
list->add(list, *sum % 10);
if (t1 != NULL) {
t1 = t1->next;
}
if (t2 != NULL) {
t2 = t2->next;
}
}
if (carry == 1) {
list->add(list, 1);
}
free(sum);
sum = NULL;
return list;
}
力扣上的代码,如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2);
int addNum(struct ListNode *n1, struct ListNode *n2, int *sum, int carry) {
int num1 = 0;
int num2 = 0;
if (n1 != NULL) {
num1 = n1->val;
}
if (n2 != NULL) {
num2 = n2->val;
}
*sum = num1 + num2 + carry;
return *sum >= 10 ? 1 : 0;
}
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
int *sum = (int *) malloc(sizeof(int));
struct ListNode *t1 = l1;
struct ListNode *t2 = l2;
int carry = 0;
struct ListNode* list = (struct ListNode*)malloc(sizeof(struct ListNode));
list->val = 0;
list->next = NULL;
struct ListNode* temp= list;
while (t1 != NULL || t2 != NULL) {
carry = addNum(t1, t2, sum, carry);
temp->val = *sum % 10;
if((t1!=NULL&&t1->next!=NULL)||(t2!=NULL&&t2->next!=NULL)){
struct ListNode* next = (struct ListNode*)malloc(sizeof(struct ListNode));
next->next=NULL;
temp->next=next;
temp = temp->next;
}
if (t1 != NULL) {
t1 = t1->next;
}
if (t2 != NULL) {
t2 = t2->next;
}
}
if (carry == 1) {
struct ListNode* next = (struct ListNode*)malloc(sizeof(struct ListNode));
next->next=NULL;
temp->next=next;
temp = temp->next;
temp->val = 1;
}
free(sum);
sum = NULL;
return list;
}
力扣评论的解法大体差不多,这边就不在一一列举了
总结
以上就是我所知道的两数相加解法,如果还有其他解法或者错误的地方欢迎各位小伙伴提出