链表应该是面试时被提及最频繁的数据结构,链表的结构很简单,它由指针把若干个节点连接成链状结构。
链表的创建、插入节点、删除节点等操作都只需要20行左右的代码就能实现,因此适合面试时提问。
常见的面试题有:
1)从尾到头打印链表;
2)删除链表的节点;
3)删除链表中倒数第k个结点;
4)反转链表;
5)合并两个排序的链表;
6)两个链表的第一个公共结点;
7)判断链表中是否有环;
8)判断一个链表是否为回文;
对应的解题思路为:
1)首先从头到尾打印这个链表,将打印的值放入一个栈中,然后从栈中依次弹出元素。依赖栈的后入先出的结构实现了从尾到头打印链表。
2)输入:将被删除的节点Node
将这个节点的数值赋值为下一个节点的数值,然后让它指向下下个节点.
Node.val=Node.next.val
Node.next=Node.next.next
也就是将下一个节点赋值给这个节点来实现删除这个节点的操作。
3) 在链表中,因为内存不是连续的,表示节点的位置需要一个辅助的指针来实现。
比如说要找倒数第k个结点,那么就使用两个指针,fast在slow指针的前k个位置点,当fast指向none时,slow就指向倒数第k个结点。
class Solution(object):
def removeNthFromEnd(self, head, n):
slow=fast=dummy=ListNode(0)
dummy.next=head
for i in range(n+1):
fast=fast.next
while fast:
slow=slow.next
fast=fast.next
slow.next=slow.next.next
return dummy.next #考虑删除的是head的情况
4)使用迭代的方法,依次保存下一个节点–>让这个节点指向上一个节点–>继续遍历下一个保存的节点。
pre=None
while head:
Next=head.next
head.next=pre
pre=head
head=Next
return pre
5)采用递归的方法,每次比较链表最开始的两个节点,并将较小的一个值接在后面,然后依次比较后面的节点。
if not l1:
return l2
if not l2:
return l1
if l1.val>l2.val:
a,b=l2,l1
else:
a,b=l1,l2
a.next=self.sort(a.next,b)
return a
思考:如果是对两个已排序的数组合并呢?要求空间复杂度为O(1)
在合并两个数组时,如果从前往后幅值每个数字(字符)则需要重复移动数字(字符)多次,那么我们可以考虑从后往前幅值,这样就能减少移动的次数,从而提高效率。
6)当两个单链表有公共结点之后,它们后面的所有结点都是一样的。因此如果我们可以从最后面的数据开始比较,找到最后一个相同的节点就是第一个公共结点,可以使用栈来存储两个链表的节点来实现,可是这样需要O(M+N)的空间复杂度。不能从头开始比较的一个重要原因是:两个链表的长度不一样。因此可以先遍历两个链表得到他们的长度,就能知道哪个链表更长,以及长的链表比短的链表长多少;在第二次遍历的时候,先让长的链表多走若干步,接着同时在两个链表上遍历,找到的第一个相同的节点就是他们的第一个公共结点。
class Solution(object):
def getIntersectionNode(self, headA, headB):
if not headA or not headB:
return None
a,b=headA,headB
while a is not b:
a=a.next if a else headB #注意这里是if a而不是a.next
b=b.next if b else headA
return a
为了考虑两者之间没有公共结点的情况,所以a=b=None的情况在第二次遍历时也存在。
7)从一个新颖的角度出发,如果链表中有环,那么两个人以不同的速度在环中跑,总有一天会遇到,如果一直遇不到说明没有环。
try:
slow=head
fast=head.next #一开始就设置slow和fast的步长不同,好处是在输入为[]时fast报错,否则两者相等。
if slow is not fast:
slow=slow.next
fast=fast.next.next
return True
except AttributeError as e:
return False
8)回文的性质是从前往后读与从后往前读相同,也就是链表数值是对称的,那么可以将链表的前半部分逆转,然后比较这个逆转后的部分与后半部分的数值是否一致。
class Solution(object):
def isPalindrome(self, head):
pre=None
slow=fast=head
while fast and fast.next:
fast=fast.next.next
Next=head.next
head.next=pre
pre=head
head=Next
if fast:
head=head.next
while pre and pre.val == head.val:
pre=pre.next
head=head.next
if not pre and not head:
return True
else:
return False