算法-快慢指针

一、“判断单链表是否有环”

我们就可以设置一个慢指针和一个快指针来遍历这个链表。慢指针一次移动一个节点,而快指针一次移动两个节点,如果该链表没有环,则快指针会先遍历完这个表,如果有环,则快指针会在第二次遍历时和慢指针相遇。

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值