六、链表
1. 使用python定义链表结构
from util.Empty import Empty
from util.Outbound import Outbound
class Node():
def __init__ (self, value = None, next = None):
self.value = value
self.next = next
class LinkedList():
def __init__(self):
self.head = Node()
self.tail = None
self.length = 0
def peek(self):
if not self.head.next:
raise Empty( 'LinkedList is empty' )
return self.head.next
def get_first(self): # 得到第一个元素
if not self.head.next:
raise Empty( 'LinkedList is empty' )
return self.head.next
def get_last(self): # 得到最后一个元素
if not self.head.next:
raise Empty( 'LinkedList is empty' )
node = self.head
while node.next != None:
node = node.next
return node
def get(self, index): # 按索引得到元素
if (index < 0 or index >= self.length):
raise Outbound( 'index is out of bound' );
if not self.head.next:
raise Empty( 'LinkedList is empty' )
node = self.head.next
for i in range(index):
node = node.next
return node
def add_first(self, value):
node = Node(value, None)
node.next = self.head.next
self.head.next = node
self.length += 1
def add_last(self, value):
new_node = Node(value)
node = self.head
while node.next != None:
node = node.next
node.next = new_node
self.length += 1
def add(self, index, value):
if (index < 0 or index > self.length):
raise Outbound( 'index is out of bound' )
if not self.head.next:
raise Empty( 'LinkedList is empty' )
new_node = Node(value)
node = self.head
for i in range(index):
node = node.next
new_node.next = node.next;
node.next = new_node;
self.length += 1
def remove_first(self):
if not self.head.next:
raise Empty( 'LinkedList is empty' )
value = self.head.next
self.head.next = self.head.next.next
self.length -= 1
return value
def remove_last(self):
if not self.head.next:
raise Empty( 'LinkedList is empty' )
node = self.head.next
prev = self.head
while node.next != None:
prev = node
node = node.next
prev.next = None
return node.value
def remove(self, index):
if (index < 0 or index >= self.length):
raise Outbound( 'index is out of bound' );
if not self.head.next:
raise Empty( 'LinkedList is empty' )
node = self.head
for i in range(index):
node = node.next
result = node.next;
node.next = node.next.next;
self.length += 1
return result;
def printlist(self):
node = self.head.next
count = 0
while node and count<20:
print(node.value, end = " ")
node = node.next
count = count + 1
print('')
2. 删除链表中的节点
- leetcode: 第237题. 删除链表中的节点,只允许访问要删除的那个节点。 难度:简单
- leetcode: 面试题18. 删除链表的节点 与此题要求不一样,有可能包括尾节点也要删除
# 传统的方法是找到prev节点,然后让prev.next = prev.next.next
# 现在不让访问prev了,只允许访问当前的node
def delete_node(node):
print(node.value)
node.value = node.next.value # 偷梁换柱,把下一个节点的value赋值给当前节点的值,删除下一个节点即可。
node.next = node.next.next
3. 找到链表的中间节点
- leetcode 第876题. 链表的中间结点 难度:简单
# 快慢指针思想
def find_middle(lst):
assert lst.head is not None and lst.head.next is not None
head = lst.head
fast = head
slow = head
while fast is not None and fast.next is not None:
fast = fast.next.next
slow = slow.next
return slow.value
4. 确定链表是不是环形的
- leetcode 第141题. 环形链表 难度:简单
def has_cycle(lst): return has_cycle_helper(lst.head) def has_cycle_helper(head): if head is None: return False slow = head fast = head while fast is not None and fast.next is not None: fast = fast.next.next slow = slow.next if slow == fast: # 环形的赛道一定会相遇 return True return False
5. 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
- leetcode 第142题. 环形链表 II 难度:中等
- 面试题 02.08. 环路检测 难度:中等
def find_beginning(head):
fast = head
slow = head
meet = None
while fast and fast.next is not None:
fast = fast.next.next
slow = slow.next
if fast == slow:
meet = fast
break
if meet is None or meet.next is None:
return None
while head and meet:
if head == meet:
return meet
head = head.next
meet = meet.next
return None
6.
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
- leetcode 第19题. 删除链表的倒数第N个节点 难度:中等
- 面试题22. 链表中倒数第k个节点 难度:简单
- 面试题 02.02. 返回倒数第 k 个节点
def remove_nth(lst, n): assert n<=lst.length and n > 0 fast = lst.head while n > 0: fast = fast.next n = n - 1 if fast == None: return head slow = lst.head while fast.next is not None: fast = fast.next slow = slow.next result = slow.next slow.next = slow.next.next lst.length = lst.length - 1 return result
7. 把链表从中间切开成两个链表
def split(head):
if (head is None):
return
slow = head
fast = head
front_last_node = slow
while (fast is not None): # 先找到中间节点
front_last_node = slow
slow = slow.next
fast = fast.next.next if fast.next is not None else None
front_last_node.next = None
front = head
back = slow
return (front, back)
8. 合并两个有序的链表
- leetcode 第21题. 合并两个有序链表 难度:简单
# iteratively
# O(m + n)
def mergeTwoLists1(l1, l2):
dummy = cur = Node(0)
while l1 and l2:
if l1.value < l2.value:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
cur.next = l1 or l2
return dummy.next
9. 找到两个链表的第一个公共节点
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
def getIntersectionNode(headA, headB):
curA, curB = headA, headB
lenA, lenB = 0, 0
while curA is not None:
lenA += 1
curA = curA.next
while curB is not None:
lenB += 1
curB = curB.next
curA, curB = headA, headB
if lenA > lenB:
for i in range(lenA-lenB):
curA = curA.next
elif lenB > lenA:
for i in range(lenB-lenA):
curB = curB.next
while curB != curA:
curB = curB.next
curA = curA.next
return curA
10. 插入排序
- leetcode 第147题. 对链表进行插入排序 难度:中等
# O(n^2)
def insertionSortList(head):
dummy = Node(0)
cur = head
# pre is the sorted part
# when see a new node, start from dummy
# cur is the unsorted part
while cur is not None:
pre = dummy
while pre.next is not None and pre.next.value < cur.value:
pre = pre.next
temp = cur.next # 插入
cur.next = pre.next
pre.next = cur
cur = temp
return dummy.next
11. 对链表进行排序
- leetcode 第148题. 排序链表 难度:中等
# Merge sort的思想
def sortList(head):
if head is None or head.next is None:
return head
mid = getMiddle(head)
rHead = mid.next
mid.next = None
return merge(sortList(head), sortList(rHead))
def merge(lHead, rHead):
dummyNode = dummyHead = Node(0)
while lHead and rHead:
if lHead.value < rHead.value:
dummyHead.next = lHead
lHead = lHead.next
else:
dummyHead.next = rHead
rHead = rHead.next
dummyHead = dummyHead.next
if lHead:
dummyHead.next = lHead
elif rHead:
dummyHead.next = rHead
return dummyNode.next
def getMiddle(head):
if head is None:
return head
slow = head
fast = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
return slow
12. 分隔链表
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
- leetcode 第86题. 分隔链表 难度:中等
- 面试题 02.04. 分割链表 难度:中等
def partition(head, x):
left_head = Node(None) # head of the list with nodes values < x
right_head = Node(None) # head of the list with nodes values >= x
left = left_head # attach here nodes with values < x
right = right_head # attach here nodes with values >= x
# traverse the list and attach current node to left or right nodes
while head:
if head.value < x:
left.next = head
left = left.next
else: # head.val >= x
right.next = head
right = right.next
head = head.next
right.next = None # set tail of the right list to None
left.next = right_head.next # attach left list to the right
return left_head.next # head of a new partitioned list
13.
- 面试题24. 反转链表
- leetcode 第206题. 反转链表 难度:简单
def reverse(lst):
head = lst.head # 哨兵节点
result = None
current = head.next
nxt = None
while current is not None:
nxt = current.next # 事先存储元素
current.next = result # 指向前一个元素
result = current # 赋值给新链表
current = nxt
head.next = result
14.
- leetcode 第92题. 反转链表 II 难度:中等
def reverseBetween(head, m, n):
if m == n:
return head
dummyNode = Node(0)
dummyNode.next = head
pre = dummyNode
for i in range(m - 1): # 先定位到m位置
pre = pre.next
# reverse the [m, n] nodes
result = None
current = pre.next # 再使用第一种方法反转
for i in range(n - m + 1):
nxt = current.next
current.next = result
result = current
current = nxt
pre.next.next = current
pre.next = result
return dummyNode.next
15.
- leetcode 第25题. K 个一组翻转链表 难度:困难
def reverseKGroup(head, k):
if head is None or k < 2:
return head
next_head = head
for i in range(k - 1):
next_head = next_head.next
if next_head is None:
return head
ret = next_head # 先用ret记录住当前第一个反转列表的位置,也是整个反转列表的开头,反转完返回它即可。
current = head
while next_head:
tail = current # 先用tail记录住当前current的位置
prev = None
for i in range(k):
if next_head:
next_head = next_head.next
nxt = current.next
current.next = prev
prev = current
current = nxt
tail.next = next_head or current
return ret
16.
- leetcode 第234题. 回文链表 难度:简单
- 面试题 02.06. 回文链表 难度:简单
# 找到中间节点和中间节点的前一个节点
def isPalindrome(head):
rev = None
slow = fast = head
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.value == slow.value:
slow = slow.next
rev = rev.next
return not rev
17.
Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.
- leetcode 第83题. 删除排序链表中的重复元素
def deleteDuplicates(head):
if head == None:
return head
node = head
while node.next:
if node.value == node.next.value:
node.next = node.next.next
else:
node = node.next
return head
18.
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.
- leetcode 第82题. 删除排序链表中的重复元素 II 难度:中等
def deleteDuplicates2(head):
dummy = pre = Node(0)
dummy.next = head
while head and head.next:
if head.value == head.next.value:
while head and head.next and head.value == head.next.value:
head = head.next
head = head.next
pre.next = head
else:
pre = pre.next
head = head.next
return dummy.next

浙公网安备 33010602011771号