linklist
链表也是面试中常问道的题目,链表定义简单很容易考察面试者的水平,比如在数组中很简单的题目转换成链表就有很大的变动。例如链表的插入和归并排序、查找倒数第k个节点等.
1.回文链表(234)
请判断一个链表是否为回文链表
class Solution(object):
def isPalindrome(self, head):
reverse, fast = None, head
while fast and fast.next:
fast = fast.next.next
head.next, reverse, head = reverse, head, head.next
tail = head.next if fast else head
is_palindrome = True
while reverse:
is_palindrome = is_palindrome and reverse.val == tail.val
reverse.next, head, reverse = head, reverse, reverse.next
tail = tail.next
return is_palindrome
2.求单链表的中间节点
快、慢指针实现
def find_middle_node(head):
slow, fast = head, head
fast = fast.next if fast else None
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow
3.删除无序链表中的重复项
给定一个无序的链表,去掉其重复项,并保留原顺序,例如链表1->3->1->5->5->7,去掉重复项后为1->3->5->7
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if head is None:
return head
outer = head
while outer:
inpre = outer
inner = inpre.next
while inner:
if inner.val == outer.val:
inner = inner.next
inpre.next = inner
else:
inpre = inner
inner = inner.next
outer = outer.next
return head
4.给定一个排序链表,删除所有含有重复数字的节点
输入: 1->2->3->3->4->4->5
输出: 1->2->5
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def deleteDuplicates(self, head):
if head is None:
return head
new = ListNode(None)
new.next = head
head = new
outpre = head
outer = outpre.next
flag = False
while outer:
inpre = outer
inner = inpre.next
while inner:
if inner.val == outer.val:
flag = True
inner = inner.next
inpre.next = inner
else:
inpre = inner
inner = inner.next
if flag:
outer = outer.next
outpre.next = outer
flag = False
else:
outpre = outer
outer = outer.next
return head.next
def deleteDuplicates_2(self, head):
if None == head or None == head.next:
return head
new_head = ListNode(-1)
new_head.next = head
parent = new_head
cur = head
while None != cur and None != cur.next:
if cur.val == cur.next.val:
val = cur.val
while None != cur and val == cur.val:
cur = cur.next
parent.next = cur
else:
cur = cur.next
parent = parent.next
return new_head.next
5.环形链表(141)
给定一个链表,判断链表中是否有环, 并找到第一个相交的点
思路:设置两个指针slow和fast,一个步长为1,一个步长为2进行遍历。如果有环,则slow和fast总会在某一点相遇。如果没有环,则fast会先为空,或者fast.next为空
class Solution(object):
def hasCycle(self, head, firstMeetNode):
fast = slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if slow == fast: # 有环
fast = head
while fast != slow:
fast = fast.next
slow = slow.next
firstMeetNode = fast
return True
return False
6.反转链表(206)
(循环算法,递归算法) 微软
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
def __repr__(self):
if self:
return "{} -> {}".format(self.val, repr(self.next))
class Solution(object):
'''循环算法'''
def reverseList(self, head):
dummy = ListNode(float("-inf"))
while head:
dummy.next, head.next, head = head, dummy.next, head.next
return dummy.next
class Solution2(object):
'''递归算法'''
def reverseList(self, head):
[begin, end] = self.reverseListRecu(head)
return begin
def reverseListRecu(self, head):
if not head:
return [None, None]
[begin, end] = self.reverseListRecu(head.next)
if end:
end.next = head
head.next = None
return [begin, head]
else:
return [head, head]
7.在双向链表中删除指定元素(微软)
class Node(object):
'''双向节点'''
def __init__(self, item):
self.item = item
self.next = None
self.prev = None
class DLinkedlist(object):
def __init__(self):
self._head = None
def remove(self, item):
"""删除元素"""
if self.is_empty():
return
else:
cur = self._head
if cur.item == item:
# 如果首节点的元素即是要删除的元素
if cur.next == None:
# 如果链表只有这一个节点
self._head = None
else:
# 将第二个节点的prev设置为None
cur.next.prev = None
# 将_head指向第二个节点
self._head = cur.next
return
while cur != None:
if cur.item == item:
# 将cur的前一个节点的next指向cur的后一个节点
cur.prev.next = cur.next
# 将cur的后一个节点的prev指向cur的前一个节点
cur.next.prev = cur.prev
break
cur = cur.next
8.两个链表合并为一个升序链表(微软)
class Node(object):
def __init__(self,item,next_=None):
self.item = item
self.next = next_
class Solution(object):
def mergeTwoLists(self, l1,l2):
head = Node(0)
cur = head
while l1 != None and l2 != None:
if l1.item <= l2.item:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
if l1 != None:
cur.next = l1
if l2 != None:
cur.next = l2
return head.next
9. 倒数第k个节点
题目: 找到链表的倒数第k个节点
解析: 使用两个指针fast和slow,fast先走k步,之后fast和slow一起走,
直到fast到达最后一个节点,slow就是倒数第k个节点
class Solution(object):
'''
题意:删除链表中倒数第k个结点,尽量只扫描一遍。
使用两个指针扫描,当第一个指针扫描到第k个结点后,
第二个指针从表头与第一个指针同时向后移动,
当第一个指针指向空节点时,另一个指针就指向倒数第k个结点了
'''
def removeNthFromEnd(self, head, k):
res = ListNode(0)
res.next = head
tmp = res
for i in range(0, k):
head = head.next
while head != None:
head = head.next
tmp = tmp.next
tmp.next = tmp.next.next
return res.next
10. 等概率返回链表中的一个元素
题意: 给你一个单链表,每次等概率随机返回一个元素
分析: 这里先不做详细解释,这是一个随机化算法的一种
class Solution(object):
def randNode(self, head):
res = head
cur = head.next
i = 2
while cur != None:
x = random.ranint(0,int(2**31))
j = x % i
if j == 0:
res = cur
cur = cur.next
i += 1
return ans