《程序员面试金典》--链表相加
2015-09-23 20:09
302 查看
题目描述:
《题目1》:
有两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表的首部。编写函数对这两个整数求和,并用链表形式返回结果。
给定两个链表ListNode* A,ListNode* B,请返回A+B的结果(ListNode*)。
测试样例: {1,2,3},{3,2,1}
返回: {4,4,4}
《题目2》:
如果这些数位是正向存放的,又该如何求解呢?
题目1分析(个位存放在链表头结点):
如果个位存放在链表头结点的时候,因为我们遍历链表的时候也是从链表头节点开始遍历,正好符合做加法的原则,从各位开始相加,超过10则进1,所以要用一个变量保存每次加法完以后是否有进位,这样递归相加就可以了。
需要注意的是,递归程序的退出条件是什么,两个链表不一定是一样的长的,所以递归至少也要把最长的链表遍历完,但是如果最后还存在进位,那么还需要递归一次,也就是说递归退出条件是:两个链表都为空且进位为0。
题目1代码实现如下:
[cpp] view
plaincopyprint?
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Plus {
public:
//链表首是数据的最低位
ListNode* plusAB(ListNode* a, ListNode* b) {
return plusAB1(a,b,0);
}
ListNode* plusAB1(ListNode* a,ListNode* b,int val)
{
if(a==NULL&&b==NULL&&val==0)
return NULL;
if(a!=NULL)
{
val+=a->val;
a=a->next;
}
if(b!=NULL)
{
val+=b->val;
b=b->next;
}
ListNode *c=new ListNode(val%10);
c->next=plusAB1(a,b,val/10);
return c;
}
};
题目2分析(个位存放在链表尾结点):
方法1:
如果个位存放在链表尾结点的时候,这个时候必须从链表尾部开始相加,并向前进位,但是我们遍历链表的时候只能从头节点开始遍历,我们仍然可以通过递归实现,只是和题目1递归的前后顺序不一样而已,题目1是先加法再递归,题目2是先递归再加法,也就是每次递归返回的时候需要把进位传过来,这个时候只能通过引用进行进位传递。
需要注意的是:因为两个链表不是一样的长,我们不能从让两个链表从头开始齐步递归,这样个位无法对齐,所以首先必须求出两个链表的长度,然后让长的链表先和NULL节点递归,等递归到了和短链表齐头并进的时候,再一起递归。
方法2:
所有递归存在的地方都可以用栈来实现,我们可以用栈来转换上述存储结构,将其转换为和题目1一样从头部遍历的效果。也就是设置两个堆栈,然后从头开始遍历两个链表,将其元素依次放入两个栈中,那么栈顶存放的元素便是个位数,这样和题目一就一样了,可以用尾部递归实现之。
题目2代码实现如下:
[cpp] view
plaincopyprint?
class Plus {
public:
//链表首节点是数据的最高位
ListNode* plusABL(ListNode* a,ListNode* b)
{
stack<int> sta,stb;
while(a!=NULL)
{
sta.push(a->val);
a=a->next;
}
while(b!=NULL)
{
stb.push(b->val);
b=b->next;
}
return plusABL1(sta,stb,0);
}
ListNode* plusABL1(stack<int> &sta,stack<int> &stb,int val)
{
if(sta.empty()&&stb.empty()&&val==0)
return NULL;
if(!sta.empty())
{
val+=sta.top();
sta.pop();
}
if(!stb.empty())
{
val+=stb.top();
stb.pop();
}
ListNode *c=new ListNode(val%10);
c->next=plusABL1(sta,stb,val/10);
return c;
}
};
《题目1》:
有两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表的首部。编写函数对这两个整数求和,并用链表形式返回结果。
给定两个链表ListNode* A,ListNode* B,请返回A+B的结果(ListNode*)。
测试样例: {1,2,3},{3,2,1}
返回: {4,4,4}
《题目2》:
如果这些数位是正向存放的,又该如何求解呢?
题目1分析(个位存放在链表头结点):
如果个位存放在链表头结点的时候,因为我们遍历链表的时候也是从链表头节点开始遍历,正好符合做加法的原则,从各位开始相加,超过10则进1,所以要用一个变量保存每次加法完以后是否有进位,这样递归相加就可以了。
需要注意的是,递归程序的退出条件是什么,两个链表不一定是一样的长的,所以递归至少也要把最长的链表遍历完,但是如果最后还存在进位,那么还需要递归一次,也就是说递归退出条件是:两个链表都为空且进位为0。
题目1代码实现如下:
[cpp] view
plaincopyprint?
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Plus {
public:
//链表首是数据的最低位
ListNode* plusAB(ListNode* a, ListNode* b) {
return plusAB1(a,b,0);
}
ListNode* plusAB1(ListNode* a,ListNode* b,int val)
{
if(a==NULL&&b==NULL&&val==0)
return NULL;
if(a!=NULL)
{
val+=a->val;
a=a->next;
}
if(b!=NULL)
{
val+=b->val;
b=b->next;
}
ListNode *c=new ListNode(val%10);
c->next=plusAB1(a,b,val/10);
return c;
}
};
题目2分析(个位存放在链表尾结点):
方法1:
如果个位存放在链表尾结点的时候,这个时候必须从链表尾部开始相加,并向前进位,但是我们遍历链表的时候只能从头节点开始遍历,我们仍然可以通过递归实现,只是和题目1递归的前后顺序不一样而已,题目1是先加法再递归,题目2是先递归再加法,也就是每次递归返回的时候需要把进位传过来,这个时候只能通过引用进行进位传递。
需要注意的是:因为两个链表不是一样的长,我们不能从让两个链表从头开始齐步递归,这样个位无法对齐,所以首先必须求出两个链表的长度,然后让长的链表先和NULL节点递归,等递归到了和短链表齐头并进的时候,再一起递归。
方法2:
所有递归存在的地方都可以用栈来实现,我们可以用栈来转换上述存储结构,将其转换为和题目1一样从头部遍历的效果。也就是设置两个堆栈,然后从头开始遍历两个链表,将其元素依次放入两个栈中,那么栈顶存放的元素便是个位数,这样和题目一就一样了,可以用尾部递归实现之。
题目2代码实现如下:
[cpp] view
plaincopyprint?
class Plus {
public:
//链表首节点是数据的最高位
ListNode* plusABL(ListNode* a,ListNode* b)
{
stack<int> sta,stb;
while(a!=NULL)
{
sta.push(a->val);
a=a->next;
}
while(b!=NULL)
{
stb.push(b->val);
b=b->next;
}
return plusABL1(sta,stb,0);
}
ListNode* plusABL1(stack<int> &sta,stack<int> &stb,int val)
{
if(sta.empty()&&stb.empty()&&val==0)
return NULL;
if(!sta.empty())
{
val+=sta.top();
sta.pop();
}
if(!stb.empty())
{
val+=stb.top();
stb.pop();
}
ListNode *c=new ListNode(val%10);
c->next=plusABL1(sta,stb,val/10);
return c;
}
};