一、“判断单链表是否有环”
我们就可以设置一个慢指针和一个快指针来遍历这个链表。慢指针一次移动一个节点,而快指针一次移动两个节点,如果该链表没有环,则快指针会先遍历完这个表,如果有环,则快指针会在第二次遍历时和慢指针相遇。
class Solution:
def hasCycle(self , head ):
# write code here
if not head:
return False
p = head
q = head
while q.next and q.next.next:
p = p.next
q = q.next.next
if p == q:
return True
return False
二、删除链表倒数第k个节点
设置两个指针,其中一个指针先移动k个节点。之后两个指针以相同速度移动。当那个先移动的指针遍历完成的时候,第二个指针正好处于倒数第k个节点。
class Solution:
def removeNode(self, head, k):
if not head:
return None
n, phead = 1, head
while phead.next:
phead = phead.next
n += 1
if k<1 or k>n:
return head
if n == k: #删除头节点
head = head.next
return head
p, q = head, head
while k != 0:
q = q.next
k -= 1
while q.next:
p = p.next
q = q.next
p.next = p.next.next
return head
三、两个链表的第一个公共结点:
输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
思路:两个链表的长度不一致。在p1链表尾部后遍历p2头部(p2也一样)解决长度不一致。
p1:0-1-2-3-4-5-null
p2:a-b-4-5-null
p1+p2:0-1-2-3-4-5-null-a-b-4-5-null
p2+p1:a-b-4-5-null-0-1-2-3-4-5-null
class Solution:
def FindFirstCommonNode(self , pHead1 , pHead2 ):
# write code here
p1, p2 = pHead1, pHead2
while p1!= p2:
if not p1:
p1 = pHead2
else:
p1 = p1.next
if not p2:
p2 = pHead1
else:
p2 = p2.next
return p1
四、给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
示例 1:
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
示例 2:
输入:head = [5], left = 1, right = 1
输出:[5]
第一趟:1—3—2—4—5
第二趟:1—4—3—2—5
#三指针法:思想——记翻转前后的位置。pre 记录开始翻转节点的前一位,p翻转节点,q目标节点下一位
class Solution:
def revernode(self, phead, left, right):
if not phead:
return None
if left >= right or left <= 0:
return phead
p, cnt = phead, 0
pre = Node(None)
pre.next = phead
while p is not None:
cnt += 1
if left == cnt:
while cnt < right:
q = p.next
p.next = q.next
q.next = pre.next
pre.next = q
cnt += 1
if left == 1: #记住翻转头节点的特殊情况
return pre.next
else:
return phead
else:
p = p.next
pre = pre.next
return None
#input: 1-2-3-4-5 ,2,4 1-3-2-4-5
#ouput: 1-4-3-2-5
五、删除重复项
双指针处理。
输入 [1, 2, 2, 2, 3, 3]
输出 3
思想:遇到重复时,q后移,将非重复项前移动。该函数处理后:[1, 2, 3, 2, 3, 3]
class Solution:
def DelDup(self, nums):
n = len(nums)
p, q = 0, 1
while q<n:
if nums[p] == nums[q]:
q += 1
continue
nums[p+1] = nums[1]
p += 1
q += 1
return len(nums[:p+1])
六、找出3个数之和等于0 的组合
思想:采用先排序 + 双指针 的思想
输入: [6, -2, 1, 1, 5]
输出: [-2, 1, 1]
class Solution:
def ThreeSum(self, nums):
n = len(nums)
res = []
if not nums or n < 3:
return res
nums.sort() #先排序
if nums[0] > 0:
return res #排序后第一位大于0,就不存在组合
for i in range(n):
if i>0 and nums[i] == nums[i-1]:
continue #从第2项开始去重
L = i+1
R = n-1
#以第i项为基准值,i+1到n-1项中寻找组合
while L<R:
if nums[i]+nums[L]+nums[R] == 0:
res.append(nums[i], nums[L], nums[R])
while L<R and nums[L] == nums[L+1]:
L += 1 #左指针的去重,关键点!
while L<R and nums[R] == nums[R-1]:
R -= 1 #右指针的去重,关键点!
L += 1
R -= 1
elif nums[i]+nums[L]+nums[R] > 0: #大于0时,缩小右指针
R -= 1
else: #和小于0时,扩大左指针
L += 1
return res
七、链表中环的入口结点
描述:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
输入描述:输入分为2段,第一段是入环前的链表部分,第二段是链表环的部分,后台将这2个会组装成一个有环或者无环单链表
返回值描述: 返回链表的环的入口结点即可。而我们后台程序会打印这个节点
示例1
输入:{1,2},{3,4,5} 返回值:3
说明:
返回环形链表入口节点,我们后台会打印该环形链表入口节点,即3
应用结论: 1、设置快慢指针,假如有环,他们最后一定相遇。
2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇与环入口。
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
if not pHead:
return pHead
p1, p2 = pHead, pHead
while p1.next and p1.next.next: #先找到相遇点
p2 = p2.next
p1 = p1.next.next
if p1 == p2:
break
if not p1.next: #没有相遇点时,返回None
return None
p3 = pHead
while p1 != p3: #从相遇点和链表起始点同时走,再次相遇点为环入口。
p1 = p1.next
p3 = p3.next
return p3