阅读 43

算法链表篇

删除排序链表的重复元素

题目描述

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例

输入:1->1->2

返回值:1->2

解题思路

因为链表是升序排列的,所以只要按顺序循环,如果发现下一节点的val等于当前节点的val,直接将next指向next.next即可。

class ListNode(object):
	"""docstring for ListNode"""
	def __init__(self, x):
		self.val = x
		self.next = None

class Solution(object):
	"""docstring for Solution"""
	def deleteDuplicates(self, head):
		p = head
		if p == None or p.next == None: return head
		while p.next:
			if p.val == p.next.val:
				p.next= p.next.next
			else:
				p = p.next
		return head
复制代码
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

合并两个有序链表

题目描述

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例

输入:1->2->4, 1->3->4

返回值:1->1->2->3->4->4

解题思路

新定义一个链表首节点dump指向0,当l1和l2链表均不为空时,判断l1当前节点val值与l2当前节点val值,如果l1当前节点val值大则当前指针指向l1,否则指向l2。直至循环结束,返回dump.next。

class ListNode:
	def __init__(self, x):
		self.val = x
		self.next = None

class Solution:
	"""docstring for Solution"""
	def merge(self, l1, l2):
		if not l1: return l2
		if not l2: return l1
		cur = dump = ListNode(0)
		while l1 and l2:
			if l1.val >= l2.val:
				cur.next = l2
				l2 = l2.next
				cur = cur.next
			else:
				cur.next = l1
				l1 = l1.next
				cur = cur.next
		cur.next = l1 if l1 else l2
		return dump.next
复制代码
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

反转链表

题目描述

输入一个链表,反转链表后,输出新链表的表头。

示例

输入:{1,2,3}

返回值:{3,2,1}

解题思路

定义3个listNode,一个cur(指向当前节点,初始赋值head),一个pre(指向上一个节点,初始赋值None),一个指向nex(指向下一个节点,初始赋值None)。当cur非空时,nex指向cur.next,cur.next指向pre,pre指向cur,cur指向next。

class ListNode(object):
	def __init__(self, x):
		self.val = x
		self.next = None

class Solution(object):
	def reverseList(self, pHead):
		cur = pHead
		nex = None
		pre = None
		while cur:
			nex = cur.next
			cur.next = pre
			pre = cur
			cur = nex
		return pre

node1 = ListNode(1)
node2 = ListNode(3)
node3 = ListNode(7)
node1.next = node2
node2.next = node3

solution = Solution()
h = solution.reverseList(node1)
复制代码
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

判断链表中是否有环

题目描述

判断给定的链表中是否有环 扩展: 你能给出空间复杂度O(1)的解法么?

示例

有环返回true;否则返回false

解题思路

使用快慢指针,快指针比慢指针移动快一倍,如果链表有环,则快慢指针会相遇。如果无环,快指针会循环至空,即结束循环返回false

class ListNode:
	def __init__(self, x):
		self.val = x
		self.next = None

class Solution:
	def hasCycle(self, head):
		if head:
			slow, fast = head, head.next
			while fast:
				slow = slow.next
				fast = fast.next
				if fast:
					fast = fast.next
				if fast is slow:
					return True
		return False
复制代码
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

返回链表入环节点

题目描述

给定一个链表,返回链表开始入环的第一个节点。如果链表无环,则返回null。

说明:不允许修改给定的链表。

进阶:你是否可以使用 O(1) 空间解决此题?

示例

有环返回入环的第一个节点;否则返回null

解题思路

假设相交点为a,使用快慢指针,快指针步长是慢指针的2倍,得到快慢指针相交点为b。此时慢指针从head走到a的距离加上a走到b的距离乘以2等于快指针从head走到a的距离+从a走到b的距离+从b走到a的距离+从a走到b的距离,即从head走到a的距离等于从b走到a的距离。detection指向head,跟slow指针同步往下走,相交点即入环点。

class ListNode(object):
	def __init__(self, x):
		self.val = x
		self.next = None

class Solution(object):
	def detectCycle(self, head):
		if head and head.next:
			slow = head.next
			fast = head.next.next
		else:
			return None
		while fast:
			if fast != slow:
				if fast.next:
					fast = fast.next.next
				else:
					return None
				slow = slow.next
			else:
				detection = head
				while detection != slow:
					slow = slow.next
					detection = detection.next
					return detection
复制代码
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

判断一个链表是否为回文结构

题目描述

给定一个链表,请判断该链表是否为回文结构。 扩展: 你能给出空间复杂度O(1)的解法么?

示例

是则返回true;否则返回false

解题思路

想要空间复杂度胃O(1),可以先使用快慢指针找到链表的中间点,然后将后半段链表反转,跟前半段链表进行对比,如果相等则返回true

class ListNode(object):
	"""docstring for ListNode"""
	def __init__(self, x):
		self.val = x
		self.next = None

class Solution(object):
	"""docstring for Solution"""
	def isPail_List(self, head):
		if head is None or head.next is None: return True
		if head.next.next == None: return head.val == head.next.val
		fast = slow = q = head
		while fast.next and fast.next.next:
			fast = fast.next.next
			slow = slow.next
		def reverse_List(head):
			cur = head
			nex = None
			pre = None
			while cur:
				nex = cur.next
				cur.next = pre
				pre = cur
				cur = nex
			return pre	
		p = reverse_List(slow.next)
		while p.next:
			if p.val != q.val:
				return False
			p = p.next
			q = q.next
		return p.val == q.val
复制代码
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

相交链表

题目描述

编写一个程序,找到两个单链表相交的起始节点。

示例

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3

输出:Reference of the node with value = 8 输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

解题思路

假设headA到相交点的距离为a,headB到相交点的距离为b,相交后的链表长度为c。因为a+c+b = b+c+a,分别定义p和q遍历l1和l2,遍历到链表结尾时p和q已经走过了l1和l2的差值,然后p、q分别移动到另一链表的表头。如果相交,则返回相交点,如果都遍历至null,则null==null退出循环

class ListNode(object):
	"""docstring for ListNode"""
	def __init__(self, x):
		self.val = x
		self.next = None

class Solution(object):
	"""docstring for Solution"""
	def getIntersectionNode(self, headA, headB):
		p = headA
		q = headB
		while p != q:
			p = p.next if p else headB
			q = q.next if q else headA
		return p
复制代码
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)