最近在学习链表,先做一下简单的总结:
一、链表的结构
二、链表常见的笔试题
- 合并两个排序好的链表
- 两个排序链表的交叉节点(后面详细介绍)
- 两个链表相加–最高位在头节点
- 两个链表相加–最高位在尾节点
- 判断链表是否为回文结构
- 待续………
一、链表的结构
首先介绍一下链表的结构,链表是由节点组成。节点是一种数据类型(这样说对吗?)。节点分为两部分,数据部分和下一节点部分。下一节点部分存储的是当前节点的后面一个节点。
代码实现:
class Node(object):
def __init__(self, data):
self.data = data
self.next = None
注意:定义的self.next为None,而不是Node。
一个数组或者一个链表生成一个链表,代码实现:
def LinkedList(pythonList):
if len(pythonList) == 0:
return None
dummpy = Node(pythonList[0])
p = dummpy
for i in range(1, len(pythonList)):
p.next = Node(pythonList[i])
p = p.next
return dummpy
上面pythonList就是一个列表或者一个数组。当这个列表的长度为0时,我们直接返回None。相当于这个链表为空。当链表长度不为0时,首先定义一个节点dummy,这个用于存储头节点,再定义一个p。p的作用是一个动态的指针,始终指向当前链表的最后一个节点,为什么呢?因为我们在存储节点时,只能把下一个节点存储在上一个节点的next里面。所以在for循环里面有那样两句话。存储p的下一个节点,p接着指向下一个节点,如此循环。请注意,最终返回的是dummy,因为它没有动,它始终指向头节点。所以我们只需要返回头节点,就可以获得整个链表。
二、题型解析
- 合并两个已经排序好的链表
Merge two sorted linked lists and return it as a new list. The new list should be madeby splicing together the nodes of the first two lists.
合并链表,也即是根据节点的数据大小来放入新的链表中,有两种情况:
第一是其中一个或两个为空,直接返回不为空的或任意一个均可以。
第二是都不为空,那就从头开始遍历两个链表,当然需要两个指针,比较这两个指针(l1, l2)所指的节点的数据大小,假设l1小,把小的放进去,我们能直接把另外一个大的l2放进去吗?当然不能,因为我们不知道l2和l1后面节点的大小关系啊。但是如果我们不放的话,加入刚才的l1是最后一个节点了,没有节点与l2比较了,那岂不是就要结束了,无缘无故丢掉一个节点。这时可以加一句判断,如果l1不为空,就把l1放进去,占个坑,然后再比较这个l1和刚才的那个l2的关系。
class Solution(object):
def mergeTwoLists(self, l1, l2):
newLinkedList = ListNode(0)
p = newLinkedList
# 其中一个为None,就返回另一个
if None in (l1, l2):
return l1 or l2
# l1和l2是一个链表,而且指向链表的头部
# 这一段是比较两个节点的数值大小,小的就放入新的链表中,并分别指向下一个节点
while l1 is not None and l2 is not None:
if l1.val < l2.val:
p.next = l1
l1 = l1.next
else:
p.next = l2
l2 = l2.next
p = p.next # p指向当前节点
# 这个地方的目的是为了将剩余的节点存进新的链表,比如说,上面l1.val和l2.val分别为最后一个节点,假如我们只存储了l1,还有l2没有存进来,此时l1已经是None,我们直接把l2存到最后就可以了,因为l1和l2的大小已经比过了。
if l1 is not None:
p.next = l1
else:
p.next = l2
return newLinkedList.next
上面的解释有点乱,看代码应该会比较清晰
- 两个链表的交叉节点
这个题目的意思是给定两个链表,找到一个节点,这个节点以及节点之后的数据在两个链表中是相同的。
这个问题比较的不仅仅是两个节点的数值相等,而且是两个节点的下一个节点也相等。所以说相等的节点的位置在两个链表中倒数是一致的,即这个节点在第一个链表中是倒数第二个,在另一个链表中也肯定是倒数第二个。如图所示:
所以当两个链表不一样长时,怎样比较?可以这样思考,两个指针,第一个指针遍历完第一个链表走五步,第二个指针遍历完第二个两个走六步。如果让第一个指针遍历完第一个链表之后指向第二个链表,第二个指针遍历完第二个链表之后指向第一个链表。当第二个指针指向第一个链表时,第二个指针是不是已经指向了第二个链表的第二个节点了(自己思考)。这样两个指针就同步了,就可以在对应位置进行比较了。当然有人会问,我们为什么不直接在短的链表的头所对应的长链表的位置开始比较(即a1,b2处)?那我们怎么才能获得链表的长度呢,不也是得遍历一次整个链表才能获得啊,这也是遍历了两次链表才完成的操作。
class Solution(object):
def getIntersectionNode(self, headA, headB):
if headA is None or headB is None:
return None
pa = headA
pb = headB
while pa is not pb:
if pa and pb:
print(pa.data, pb.data)
pa = headB if pa is None else pa.next
pb = headA if pb is None else pb.next
return pa
3.两个链表相加,最高位在头节点
这个题目的意思是给两个链表,每一个链表组成一个数,将这两个数相加,最后再将这个和转变成一个链表返回。
样例
给出 6->1->7 + 2->9->5。即,617 + 295。
返回 9->1->2。即,912 。
我的思路就是先将链表转换成数字,相加求和,再转变成链表,返回头节点即可。
class Node(object):
def __init__(self, data):
self.data = data
self.next = None
def LinkedList(pythonList):
if len(pythonList) == 0:
return None
dummpy = Node(pythonList[0])
p = dummpy
for i in range(1, len(pythonList)):
p.next = Node(pythonList[i])
p = p.next
return dummpy
class Solution:
"""
@param: l1: The first list.
@param: l2: The second list.
@return: the sum list of l1 and l2.
"""
def addLists2(self, l1, l2):
# write your code here
a, b, c = 0, 0, 0
while l1 is not None:
a = a * 10 + l1.data
l1 = l1.next
while l2 is not None:
b = b * 10 + l2.data
l2 = l2.next
c = a + b
print(a, b, c)
cList = str(c)
print(cList)
dummy = Node(int(cList[0]))
p = dummy
for i in range(1, len(cList)):
p.next = Node(int(cList[i]))
p = p.next
return dummy
4.两个链表相加,最高位在头节点
这个和上一个思路是一样的,只是在处理数据方面略有不同
class Solution:
# @param l1: the first list
# @param l2: the second list
# @return: the sum list of l1 and l2
def addLists(self, l1, l2):
# write your code here
head = ListNode(0)
p = head
a, b, c = 0, 0, 0
i = 0
while l1 is not None:
a = a + l1.val * (10 ** i)
l1 = l1.next
i = i + 1
i = 0
while l2 is not None:
b = b + l2.val * (10 ** i)
l2 = l2.next
i = i + 1
c = a + b
c = str(c)
for num in c[::-1]:
p.next = ListNode(int(num))
p = p.next
return head.next
5.判断链表是否为回文结构
回文结构就是第一个和最后一个的值相等第二个和倒数第二个,依次类推。思路就是,两个指针,一个快一个慢,快指针走两步,慢指针走一步,快指针走到最后,慢指针走到中间后面一个,同时将前面半个链表反转,这样就从中间开始向两边行走,对应位置相比较即可:
class Solution:
"""
@param: head: A ListNode.
@return: A boolean.
"""
def isPalindrome(self, head):
# write your code here
slow = fast = head
rev = None
while fast and fast.next:
fast = fast.next.next
rev, rev.next, slow = slow, rev, slow.next
if fast:
slow = slow.next
while rev and rev.val == slow.val:
rev = rev.next
slow = slow.next
return not rev