小白被力扣第2题折磨的心路历程

初次看到这个题,我的想法是先将输入中两个逆序的链表还原出来,由于不知道输入链表的长度,所以先统计l1,l2的位数,即链表的长度:

int bit1 = 0;
int bit2 = 0; // 统计位数bit
ListNode* temp1 = l1;
ListNode* temp2 = l2; // 防止移动头指针
while (temp1 != NULL)
{
	bit1++;
	temp1 = temp1->next;
}
while (temp2 != NULL)
{
	bit2++;
	temp2 = temp2->next;
}
//算出了两个数的位数bit1,bit2

知道了位数后,开始还原l1,l2中正序代表的数字,由于逆序存储分别代表实际数字的个、十、百...位,所以可以用pow函数:

int num1 = 0;
int num2 = 0; // 待逆序存储的数字
ListNode* temp11 = l1;
ListNode* temp22 = l2; // 防止移动头指针
for (int i = 0; i < bit1; i++)
{
	num1 += temp11->val * pow(10, i);
	temp11 = temp11->next;
}
for (int i = 0; i < bit2; i++)
{
	num2 += temp22->val * pow(10, i);
	temp22 = temp22->next;
}
int sum = num1 + num2; // 计算出最终存储的逆序前的数

至此,算出了要存储到链表中返回的数,现在将其逆序存储到返回链表中,需要知道sum的位数count,即代表了链表的节点数:

	int temp = sum; // 防止直接对sum操作导致sum值改变
	int count = 1; // sum的位数
	while (temp / 10 != 0) // 统计sum的位数
	{
		temp /= 10;
		count++;
	}
	//count是最后和的位数,sum是最后和的值

有了位数之后,由于将整数的每位单独存储非常麻烦,想到了用to_string函数将sum转化成字符串,最后利用字符数组把每位还原成int型进行存储:

ListNode* head = new ListNode;
	head->val = NULL;
	head->next = NULL;
	ListNode* current = head; // 防止移动头指针

	string sum_str = to_string(sum); // 将最后和结果转换为字符串,方便逆序存储

	// 没有头节点,先对第一位进行操作,类似于初始化头节点
	int digit_value = sum_str[count - 1] - '0'; // char型转化为int型需要减去'0'的ASCII码
	current->val = digit_value;

	// 再对头节点后的数进行操作
	for (int i = count - 1; i > 0; i--)
	{
		ListNode* temp = new ListNode;
		int digit_value = sum_str[i - 1] - '0';
		temp->val = digit_value;
		current->next = temp;
		current = current->next;
	}
	// 最后节点的指针指向空
	current->next = NULL;
	return head;

注意:这里采用的是没有头节点的链表。

这种方法可以通过力扣运行时的3个简单测试用例

 但是,当提交时发现问题:

如果测试用例中的链表过长,即数字过大,会导致超出int所能表示的范围,所以这种方法不可行。

在看了b站上关于第二题的讲解后,我更新了我的算法:

首先,观察题目中的链表,发现如果按位逆序相加(带进位),然后直接按位存储,也可以实现最终的结果。这是因为数学计算中,也是按照个、十、百...的顺序进行进位的。所以,并不需要将l1、l2中的数字还原出来,直接单独计算每位的总和(sum),然后用总和算出个位(即要存在返回链表节点的数)、进位即可,总和=l1对应节点的值+l2对应节点的值+进位(初始化为0,默认第一次计算前没有进位),然后遍历l1,l2两个链表。

int sum = 0; // 两位总和
int data = 0;// 个位
int bit = 0; // 进位
ListNode* res; // 指针不会调用构造和析构函数,只是定义了一个指针,没有申请内存
res = new ListNode; // 使用new创建对象时,申请分配内存,调用构造函数
ListNode* current = res;
while (l1 != NULL && l2 != NULL)
{
	ListNode* temp;
	temp = new ListNode;
	sum = l1->val + l2->val + bit; // 在这里加上进位
	bit = sum / 10;
	data = sum % 10;
	temp->val = data;
	current->next = temp;
	l1 = l1->next;
	l2 = l2->next;
	current = current->next;
}

l1,l2不一定等长,当任何一个遍历完时,还需要检查一下对方遍历完没:

while (l1 != NULL)
{
	ListNode* temp;
	temp = new ListNode;
	sum = l1->val + bit;
	bit = sum / 10;
	data = sum % 10;
	temp->val = data;
	current->next = temp;
	l1 = l1->next;
	current = current->next;
}
while (l2 != NULL)
{
	ListNode* temp;
	temp = new ListNode;
	sum = l2->val + bit;
	bit = sum / 10;
	data = sum % 10;
	temp->val = data;
	current->next = temp;
	l2 = l2->next;
	current = current->next;
}

l1,l2都遍历完后,再检查进位是否为0,若不为0,还需要创建一个新的节点存放进位:

if (bit != 0)
{
	ListNode* temp;
	temp = new ListNode;
	temp->val = bit;
	current->next = temp;
	current = current->next;
}

由于采用的是带头结点(方便插值)的链表,所以最终返回res->next:

return res->next;

至此,本题得解。

第一次做题的源代码:

#include<iostream>
#include<string>
using namespace std;

struct ListNode
{
	int val;
	ListNode* next;
	ListNode() : val(0), next(nullptr) {}
	ListNode(int x) : val(x), next(nullptr) {}
	ListNode(int x, ListNode* next) : val(x), next(next) {}
};

class Solution {
public:
	ListNode* addTwoNumbers(ListNode* l1, ListNode* l2)
	{
		int bit1 = 0;
		int bit2 = 0; // 统计位数bit
		ListNode* temp1 = l1;
		ListNode* temp2 = l2; // 防止移动头指针
		while (temp1 != NULL)
		{
			bit1++;
			temp1 = temp1->next;
		}
		while (temp2 != NULL)
		{
			bit2++;
			temp2 = temp2->next;
		}
		//算出了两个数的位数bit1,bit2
		int num1 = 0;
		int num2 = 0; // 待逆序存储的数字
		ListNode* temp11 = l1;
		ListNode* temp22 = l2; // 防止移动头指针
		for (int i = 0; i < bit1; i++)
		{
			num1 += temp11->val * pow(10, i);
			temp11 = temp11->next;
		}
		for (int i = 0; i < bit2; i++)
		{
			num2 += temp22->val * pow(10, i);
			temp22 = temp22->next;
		}
		int sum = num1 + num2; // 计算出最终存储的逆序前的数
		int temp = sum;
		int count = 1;
		while (temp / 10 != 0) // 统计sum的位数
		{
			temp /= 10;
			count++;
		}
		//count是最后和的位数,sum是最后和的值

		ListNode* head = new ListNode;
		head->val = NULL;
		head->next = NULL;
		ListNode* current = head; // 防止移动头指针

		string sum_str = to_string(sum); // 将最后和结果转换为字符串,方便逆序存储

		// 没有头节点,先对第一位进行操作,类似于初始化头节点
		int digit_value = sum_str[count - 1] - '0'; // char型转化为int型需要减去'0'的ASCII码
		current->val = digit_value;

		// 再对头节点后的数进行操作
		for (int i = count - 1; i > 0; i--)
		{
			ListNode* temp = new ListNode;
			int digit_value = sum_str[i - 1] - '0';
			temp->val = digit_value;
			current->next = temp;
			current = current->next;
		}
		// 最后节点的指针指向空
		current->next = NULL;
		return head;
	}


};

void test()
{
	ListNode* l1 = new ListNode;
	l1->val = 5;
	ListNode* node12 = new ListNode;
	node12->val = 6;
	l1->next = node12;
	ListNode* node13 = new ListNode;
	node13->val = 4;
	node12->next = node13;

	ListNode* l2 = new ListNode;
	l2->val = 2;
	ListNode* node22 = new ListNode;
	node22->val = 4;
	l2->next = node22;
	ListNode* node23 = new ListNode;
	node23->val = 3;
	node22->next = node23;

	Solution s;
	ListNode* res = s.addTwoNumbers(l1, l2);
	cout << res->val << " " << res->next->val << " " << res->next->next->val << endl;

	// 结果:可以满足题目要求,但是无法满足l1,l2中存放过大数据的情况,因为int类型能存储的位数有限,见39、44行
	// 结论:我写的这种方法不适用
}

int main()
{
	test();
	system("pause");
}

第二次做题的源代码:

#include<iostream>
#include<string>
using namespace std;

struct ListNode
{
	int val;
	ListNode* next;
	ListNode() : val(0), next(nullptr) {}
	ListNode(int x) : val(x), next(nullptr) {}
	ListNode(int x, ListNode* next) : val(x), next(next) {}
};

class Solution {
public:
	ListNode* addTwoNumbers(ListNode* l1, ListNode* l2)
	{
		int sum = 0; // 两位总和
		int data = 0;// 个位
		int bit = 0; // 进位
		ListNode* res; // 指针不会调用构造和析构函数,只是定义了一个指针,没有申请内存
		res = new ListNode; // 使用new创建对象时,申请分配内存,调用构造函数
		// 此时的res!=NULL,因为res内有val=0
		// res->next为NULL
		ListNode* current = res;
		while (l1 != NULL && l2 != NULL)
		{
			ListNode* temp;
			temp = new ListNode;
			sum = l1->val + l2->val + bit; // 在这里加上进位
			bit = sum / 10;
			data = sum % 10;
			temp->val = data;
			current->next = temp;
			l1 = l1->next;
			l2 = l2->next;
			current = current->next;
		}
		while (l1 != NULL)
		{
			ListNode* temp;
			temp = new ListNode;
			sum = l1->val + bit;
			bit = sum / 10;
			data = sum % 10;
			temp->val = data;
			current->next = temp;
			l1 = l1->next;
			current = current->next;
		}
		while (l2 != NULL)
		{
			ListNode* temp;
			temp = new ListNode;
			sum = l2->val + bit;
			bit = sum / 10;
			data = sum % 10;
			temp->val = data;
			current->next = temp;
			l2 = l2->next;
			current = current->next;
		}
		if (bit != 0)
		{
			ListNode* temp;
			temp = new ListNode;
			temp->val = bit;
			current->next = temp;
			current = current->next;
		}
		return res->next;
	}
};

void test()
{
	ListNode* l1 = new ListNode;
	l1->val = 5;
	ListNode* node12 = new ListNode;
	node12->val = 6;
	l1->next = node12;
	ListNode* node13 = new ListNode;
	node13->val = 4;
	node12->next = node13;

	ListNode* l2 = new ListNode;
	l2->val = 2;
	ListNode* node22 = new ListNode;
	node22->val = 4;
	l2->next = node22;
	ListNode* node23 = new ListNode;
	node23->val = 3;
	node22->next = node23;

	Solution s;
	ListNode* res = s.addTwoNumbers(l1, l2);
	cout << res->val << " " << res->next->val << " " << res->next->next->val << endl;
}

int main()
{
	test();
	system("pause");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值