双指针解决链表问题(python)

双指针技巧:左右指针和快慢指针
左右指针:两个指针相向而行或相背而行
快慢指针:两个指针同向而行,一快一慢

1、合并两个有序链表

class ListNode:
	def __init__(self, val=0, next=None):
		self.val = val
		self.next = next
class Solution:
	def mergeTwoList(self, list1, list2):
		# 构建虚拟头节点dummy
		dummy  = ListNode(-1)
		p = dummy
		p1 = list1
		p2 = list2
		while p1 and p2:
			if p1.val > p2.val:
				p.next = p2
				p2 = p2.next
			else:
				p.next = p1
				p1 = p1.next
			# 要注意p指针要不断前进
			p = p.next
		if p1:
			p.next = p1
		if p2:
			p.next = p2
		return dummy.next

需要构建虚拟头节点的情况:
当需要创造一条新链表的时候,可以使用虚拟头节点简化边界情况的处理。

2、分割链表

给定一个 链表的头节点和一个特定值x,对链表进行分割,使所有小于x的节点都出现在大于或等于x的节点之前。

class ListNode:
	def __init__(self, val=0, next=None):
		self.val = val
		self.next = next
class Solution:
	def SegmTwoList(self, head: ListNode, x: int)->ListNode:
		dummy1, dummy2 = ListNode(-1), ListNode(-1)
		# 用两个指针指向虚拟头节点,生成结果链表
		p1, p2 = dummy1, dummy2
		p = head
		while p:
			if p.val < x:
				p1.next = p
				p1 = p1.next
			else:
				p2.next = p
				p2 = p2.next
			# 断开原链表中每个节点的next指针
			# 也就是断开节点之间的连接
			temp = p.next
			p.next = None
			p = temp
		# 连接两个链表,dummy2是完整的链表,p2只有一个 节点
		p1.next = dummy2.next
		return dummy1.next

3、合并k个有序链表

两两合并,分而治之

class ListNode:
	def __init__(self, val=0, next=None):
		self.val = val
		self.next = next
class Solution:
	def mergeKList(self, lists:List[Optional[ListNode]])->Optional[ListNode]:
		if not len(lists): return None
		return self.merge(lists, 0, len(lists)-1)
	def merge(self, lists, l, r):
		if l == r: return lists[l]
		m = l+(r-1)//2
		return self.mergeTwoLists(self.merge(lists, l, m), self.merge(lists, m+1, r)
	def mergeTwoLists(self, list1, list2):
		dummy = ListNode(-1)
		p = dummy
		p1, p2 = list1, list2
		while p1 and p2:
			if p1.val > p2.val:
				p.next = p2
				p2 = p2.next
			else:
				p.next = p1
				p1 = p1.next
			p = p.next
		if p1:
			p.next = p1
		if p2:
			p.next = p2
		return dummy.next

4、单链表的倒数第k个节点

设置两个指针,一个指针先走k步,然后再同时向前走,等第一个指针走完,第二个指针所指的就是倒数第k个节点

def findK(head, k):
	p1 = head
	for i in range(k):
		p1 = p1.next
	p2 = head
	while p1:
		p1 = p1.next
		p2 = p2.next
	return p2

5、单链表的中点

快慢指针,一个走两步,一个走一步,两步的走到底,那一步的指针指向的就是单链表中点

def middleNode(head):
	p1, p2 = head, head
	while p1.next and p1:
		p1 = p1.next.next
		p2 = p2.next
	return p2

6、判断链表是否有环

也是利用快慢指针,一个走两步,一个走一步,若两个指针相遇,则说明有环,若快指针为空,则说明无环

def isCycle(head):
	p1, p2 = head, head
	while p1.next and p1:
		p1 = p1.next.next
		p2 = p2.next
		if p1 == p2:
			return True
	return False

若有环,返回链表开始如环的第一个节点,若无环返回空

若有环,那么假设慢指针走了k步,则快指针走了2k步,若假设相遇点距环起点为m,则头节点距环起点为k-m步,相遇点也距环起点k-m步。也就是说,从头开始与从相遇点开始走到两个指针相遇的时候就是环起点了。

def detCycle(head):
	p1, p2 = head, head
	while p1.next and p1:
		p1 = p1.next.next
		p2 = p2.next
		if p1 == p2:
			break
	if not p1 or not p1.next:
		return None
	p1 = head
	while p1 != p2:
		p1 = p1.next
		p2 = p2.next
	return p1

7、两个链表是否相交

def getIntersection(headA, headB):
	p1, p2 = headA, headB
	while p1 != p2:
		if not p1:
			p1 = headB
		else:
			p1 = p1.next
		if not p2:
			p2= headA
		else:
			p2 = p2.next
	return p1

循环条件是p1!=p2,若不相交,那么经过添加不同链表到结尾,遍历到最后也会在空节点相交,也就是返回的值为空。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值