1、判断一个链表是否为回文结构
给定一个链表的头节点head,请判断该链表是否为回文结构。
例如: 1->2->1,返回true。 1->2->2->1,返回true。
15->6->15,返回true。 1->2->3,返回false。
进阶:如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1)。
思路1:遍历过程中,将所有结果放入栈,查看逆序和原结构是否一样,空间复杂度o(N)
思路2:将中间后面的结果放入栈,然后一起遍历比较,0(N/2)
思路3:慢指针指向中间位置,并使元素指向空,快指针指向中间多一个,然后将后面元素指向前面。空间复杂度o(1)
from queue import LifoQueue
class Node:
def __init__(self, data, next=None):
self.value = data
self.next = next
class IsPalindromeList:
def stack_method(self, head):
stack_ = LifoQueue()
cur = head
while cur is not None:
stack_.put(cur)
cur = cur.next
while head is not None:
if head.value != stack_.get().value:
return False
head = head.next
return True
# need n/2 extra space
def stack_method2(self, head):
if head == None or head.next is None:
return True
right = head.next
cur = head
while cur.next is not None and cur.next.next is not None:
right = right.next
cur = cur.next.next
stack_ = LifoQueue()
while right is not None:
stack_.put_nowait(right)
right = right.next
while not stack_.empty():
if head.value != stack_.get().value:
return False
head = head.next
return True
# need O(1) extra space
def no_stack_method(self, head):
if head == None or head.next == None:
return True
n1 = head
n2 = head
while n2.next != None and n2.next.next != None: # find mid node
n1 = n1.next # mid node
n2 = n2.next.next # end node
n2 = n1.next # right part first node
n1.next = None # mid.next-> None
while n2 != None: # right part revert
n3 = n2.next # save next node
n2.next = n1 # next of right node convert
n1 = n2 # n1 move
n2 = n3 # n2 move
# n2.next, n1 = n1, n2
n3 = n1 # save last node
n2 = head # left first node
res =True
while n1 != None and n2 != None:
if n1.value != n2.value:
res = False
break
n1 = n1.next
n2 = n2.next
# final recover linked list
n1 = n3.next
n3.next = None
while n1 != None:
n2 = n1.next
n1.next = n3
n3 = n1
n1 = n2
return res
def print_linked_list(self, node):
print('Linked List: ')
while node != None:
print(node.value, ' ')
node = node.next
print()
def main(self):
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
head.next.next.next = Node(1)
self.print_linked_list(head)
print(self.stack_method(head) , ' | ')
print(self.stack_method2(head) , ' | ')
print(self.no_stack_method(head) , ' | ')
self.print_linked_list(head)
print("1=========================")
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
head.next.next.next = Node(2)
head.next.next.next.next = Node(1)
self.print_linked_list(head)
print(self.stack_method(head) , ' | ')
print(self.stack_method2(head) , ' | ')
print(self.no_stack_method(head) , ' | ')
self.print_linked_list(head)
print("2=========================")
a = IsPalindromeList()
a.main()
2、荷兰国旗链表问题
思路1: 直接将节点放入数组结构,排序后,遍历连接。空间复杂度O(N)
思路2: 空间复杂度o(1), 准备六个变量标记start和end的变量less, eq, more, 还有一个临时标记下一个数
- 遍历,将对应的值挂到对应遍历下面
- 最后将三个变量连接
class Node:
def __init__(self, value, next=None):
self.value = value
self.next = next
class SmallerEqualBigger:
def list_partition1(self, head, pivot):
if head is None:
return head
cur = head
i = 0
while cur is not None:
i += 1
cur = cur.next
node_arr = [i for i in range(i)] # 构造总长度列表
i = 0
cur = head
for i in range(len(node_arr)):
node_arr[i] = cur
cur = cur.next
self.arr_partition(node_arr, pivot)
for i in range(1, len(node_arr)):
node_arr[i-1].next = node_arr[i]
node_arr[i-1].next = None
return node_arr[0]
def arr_partition(self, node_arr, pivot):
small = -1
big = len(node_arr)
index = 0
while index != big:
if node_arr[index].value < pivot:
small += 1
node_arr[small], node_arr[index] = node_arr[index], node_arr[small]
index += 1
elif node_arr[index].value == pivot:
index += 1
else:
big -= 1
node_arr[big], node_arr[index] = node_arr[index], node_arr[big]
def list_partition2(self, head, pivot):
sh, st, eh, et, bh, bt, next = [None for _ in range(7)]
while head != None:
next = head.next
head.next = None
if head.value < pivot:
if sh is None:
sh,st = head,head
else:
sh.next, st = head, head
elif head.value == pivot:
if eh is None:
eh,et = head,head
else:
eh.next, et = head,head
else:
if bh is None:
bh,bt = head,head
else:
bh.next,bt = head,head
head = next
if st is not None:
st.next = eh
et = st if et is None else et # 不存在相等区域情况
if et is not None:
et.next = bh
# return sh if sh is not None else eh if eh is not None else bh
if sh is not None:
return sh
else:
if eh is not None:
return eh
else:
return bh
def print_linked_list(self, node):
print('Linked List: ')
while node != None:
print(node.value, '')
node = node.next
print()
def main(self):
head1 = Node(7)
head1.next = Node(9)
head1.next.next = Node(1)
head1.next.next.next = Node(8)
head1.next.next.next.next = Node(5)
head1.next.next.next.next.next = Node(2)
head1.next.next.next.next.next.next = Node(5)
self.print_linked_list(self.list_partition1(head1, 5))
self.print_linked_list(self.list_partition2(head1, 5))
SmallerEqualBigger().main()
3、 复制含有随机指针节点的链表
Node类中的value是节点值,next指针和正常单链表中next指针的意义
一 样,都指向下一个节点,rand指针是Node类中新增的指针,这个指
针可 能指向链表中的任意一个节点,也可能指向null。 给定一个由
Node节点类型组成的无环单链表的头节点head,请实现一个 函数完成
这个链表中所有结构的复制,并返回复制的新链表的头节点。 进阶:
不使用额外的数据结构,只用有限几个变量,且在时间复杂度为 O(N)
内完成原问题要实现的函数。
思路1:准备哈希表,将原节点和新节点以kv形式存入,遍历
思路2:复制原节点,
1、重新构造链表为1->1’->2->2’->3->3’
2、一次取出两个节点,假如节点1和1’,主要获取rand指针问题,这里1的rand指针为3,而3的next指针为3’
3、然后设置1’的rand指向3’,依次就可以完成全部复制
class Node:
def __init__(self, value, next=None, rand=None):
self.value = value
self.next = next
self.rand = rand
class CopyListWithRandom:
def copy_random_linked(self, head):
map = {}
cur = head
while cur is not None:
map[cur] = Node(cur.value)
cur = cur.next
cur = head
while cur is not None:
map[cur].next = map[cur.next] if cur.next is not None else None
map[cur].rand = map[cur.rand] if cur.next is not None else None
cur = cur.next
return map[head]
def copy_random_linked2(self, head):
if head is None:
return None
cur = head
# 1-1'-2-2'-3-3'-None
while cur is not None:
nor_next = cur.next
cur.next = Node(cur.value)
cur.next.next = nor_next # 然后1'->2
cur = nor_next
cur = head
# 设置复制node rand
while cur is not None:
nor_next = cur.next.next
cur_copy = cur.next
cur_copy.rand = cur.rand.next if cur.rand is not None else None
cur = nor_next
res = head.next
cur = head
while cur is not None:
old_node = cur.next.next
copy_node = cur.next
cur.next = old_node
copy_node.next = old_node.next if old_node is not None else None
cur = old_node
return res
def print_linked_list(self, node):
print('Linked List: ')
while node != None:
print(f'next: {node.value}, rand: {node.rand.value if node.rand is not None else None}')
node = node.next
print()
def main(self):
"""
next: 1->2->3->None
random: 1->3, 2->1, 3->None
"""
head1 = Node(1)
head1.next = Node(2)
head1.next.next = Node(3)
head1.rand = head1.next.next
head1.next.rand = head1
head1.next.next.rand = None
self.print_linked_list(self.copy_random_linked(head1))
self.print_linked_list(self.copy_random_linked2(head1))
CopyListWithRandom().main()
4、两个单链表相交问题
单链表可能有环,也可能无环。给定两个
单链表的头节点 head1和head2,这两个链表可能相交,也可能
不相交。请实现一个函数, 如果两个链表相交,请返回相交的
第一个节点;如果不相交,返回null 即可。 要求:如果链表1
的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外
空间复杂度请达到O(1)。
首先:判断有没有环
思路1:准备哈希表、先遍历A链表放入哈希表,再遍历B链表是否存在即可
思路2:准备两个变量,一个慢指针,一个快指针
- 快指针每次走两步,慢指针走一步
- 碰到即有环,然后快指针回到head,快慢各走一步就是入环的位置。反之碰到None为无环
a、都无环的情况
- 准备4个变量,head1的长度、end1、head2的长度、end2
- end1等于end2即有环,先遍历长的链表到等于另一个长度,然后一起遍历即可找出相同点
b、一有环、一无环,不可能相交,违背单链表定义
c、都有环的情况,交点三种情况: 无相交、一个交点、两个交点
- 一个交点:准备4个变量,开始判断有无环的时候,获取到了入环节点loop,loop1和2相等
- 无交点或两个交点:loop1和2不相等,继续让从loop1遍历看是否碰到loop2来判断
class Node:
def __init__(self, data, next=None):
self.value = data
self.next = next
class GetIntersectNode:
def get_intersect_node(self, head1, head2):
if head1 is None or head2 is None:
return None
loop1 = self.get_loop_node(head1)
loop2 = self.get_loop_node(head2)
# 都无环
if loop1 is None and loop2 is None:
return self.no_loop(head1, head2)
# 都有环
elif loop1 is not None and loop2 is not None:
return self.both_loop(head1, loop1, head2, loop2)
# 一个有环一个无环
return None
def get_loop_node(self, head):
if head is None or head.next is None or head.next.next is None:
return None
n1 = head.next # slow pointer
n2 = head.next.next # fast pointer
while n1 != n2:
if n2.next is None or n2.next.next is None:
return None
n2 = n2.next.next
n1 = n1.next
n2 = head
# 最后获取入环节点
while n1 != n2:
n1 = n1.next
n2 = n2.next
return n1
def no_loop(self, head1, head2):
if head1 is None and head2 is None:
return None
cur1 = head1
cur2 = head2
n = 0
while cur1.next is not None:
n += 1
cur1 = cur1.next
while cur2.next is not None:
n -= 1
cur2 = cur2.next
if cur1 != cur2:
return None
cur1 = head1 if n > 0 else head2 # 长链表
cur2 = head2 if cur1 == head1 else head2 # 短链表,相反
n = abs(n)
while n != 0:
n -= 1
cur1 = cur1.next
while cur1 != cur2:
cur1, cur2 = cur1.next, cur2.next
return cur1
def both_loop(self, head1, loop1, head2, loop2):
cur1 = None
cur2 = None
if loop1 == loop2:
cur1,cur2,n = head1,head2,0
while cur1 != loop1:
n += 1
cur1 = cur1.next
while cur2 != loop2:
n -= 1
cur2 = cur2.next
cur1 = head1 if n>0 else head2
cur2 = head2 if cur1==head1 else head1
n = abs(n)
while 0 != n:
n -= 1
cur1 = cur1.next
while cur1 != cur2:
cur1 = cur1.next
cur2 = cur2.next
return cur1
else:
cur1 = loop1.next
while cur1 != loop1:
if cur1 == loop2:
return loop1
cur1 = cur1.next
return None
def main(self):
# 一、都无环
# 1-2-3-4-5-6-7-None
head1 = Node(1)
head1.next = Node(2)
head1.next.next = Node(3)
head1.next.next.next = Node(4)
head1.next.next.next.next = Node(5)
head1.next.next.next.next.next = Node(6)
head1.next.next.next.next.next.next = Node(7)
# 0-9-8-6-7-None
head2 = Node(0)
head2.next = Node(9)
head2.next.next = Node(8)
head2.next.next.next = head1.next.next.next.next.next # 8->6
print(self.get_intersect_node(head1, head2).value) # 6
# 相同环
# 1->2->3->4->5->6->7->4...
head3 = Node(1)
head3.next = Node(2)
head3.next.next = Node(3)
head3.next.next.next = Node(4)
head3.next.next.next.next = Node(5)
head3.next.next.next.next.next = Node(6)
head3.next.next.next.next.next.next = Node(7)
head3.next.next.next.next.next.next = head3.next.next.next # 7->4
# 0->9->8->2...
head4 = Node(0)
head4.next = Node(9)
head4.next.next = Node(8)
head4.next.next.next = head3.next # 8->2
print(self.get_intersect_node(head3, head4).value) # 2
# 不相同环
# 0->9->8->6->4->5->6..
head5 = Node(0)
head5.next = Node(9)
head5.next.next = Node(8)
head5.next.next.next = head3.next.next.next.next.next # 8->6
print(self.get_intersect_node(head3, head5).value) # 6
# 6,2,6
GetIntersectNode().main()