【leetcode206/24/141】【反转单链表&链表结点两两交换&链表是否有环】

leetcode 206 反转链表

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

解题思路:

把当前的结点(cur)的next指针指向它的前驱结点,需要两个指针去记录,一个是当前结点,一个是前驱结点,循环所有的结点去反转指针即可。此为双指针迭代法

代码思路:

  • head为链表的头结点,把它设为当前指针,然后设置头结点的前驱结点prev为None,使用while循环链表,重点是关注3个变量的指针变化! 注 意 这 里 的 赋 值 是 同 时 操 作 的 \color{red}{注意这里的赋值是同时操作的} ,我是这样理解的,
  1. cur.next = prev , cur的next指针指向prev
  2. cur = cur.next , cur指针指向下一个结点,即cur.next
  3. prev = cur , prev指向下一个结点,即cur

动图演示

由此可见,其实是一个指针指向变换的过程,可以看下面动图理解:(来自leetcode)
在这里插入图片描述
在这里插入图片描述

代码:

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def reverseList(self, head):
        cur,prev = head,None
        #高效的做法:
        while cur:
            cur.next,cur,prev = prev,cur.next,cur
        return prev

		#常见做法:
		# 记录当前节点的下一个节点
			tmp = cur.next
			# 然后将当前节点指向pre
			cur.next = pre
			# pre和cur节点都前进一位
			pre = cur
			cur = tmp

复 杂 度 分 析 : \color{red}{复杂度分析:}

假设 n 是列表的长度,时间复杂度是 O(n);空间复杂度:O(1)

进阶:使用递归进行反转链表

递归解法比较难理解,不过递归始终只要关注两个关键即可:

  1. 定义一个终止条件,符合条件才继续调用,否则返回
  2. 找到本级函数和下一级函数的等价条件

这条题目的两个条件:

  1. 终止条件:当前结点或下一结点是否等于null,是就返回
  2. 函数内部改变结点指向,head的下一个结点指向head

可看动图理解:(从leetcode可找到,感谢画图者贡献)
在这里插入图片描述
head.next.next=head指的是head节点的下一个结点的next指针指向 head
如head=4,head.next就是5,head.next.next就是空,则5->4

class Solution(object):
	def reverseList(self, head):
		"""
		:type head: ListNode
		:rtype: ListNode
		"""
		# 递归终止条件是当前为空,或者下一个节点为空
		if head == None or head.next == None :
			return head
		cur = self.reverseList(head.next)  #cur为最后一个节点
		head.next.next = head
		#防止链表循环,要将head.next设为空
		head.next = None #即4->5被删除了
		return cur

复 杂 度 分 析 : \color{red}{复杂度分析:}
假设 nn是列表的长度,那么时间复杂度为 O(n)
由于使用递归,将会使用隐式栈空间。递归深度可能会达到 n 层。,空间复杂度为O(n)

leetcode 24 两两交换链表中的节点

示例:

给定 1->2->3->4, 你应该返回 2->1->4->3.
提示(还有一题是按照固定范围交换结点的,可以去找找)

解题思路:

  • 迭代法。找到一个空的节点,连接head,循环链表,若节点为空或者下一个结点为空,那么说明当前没有结点或只有一个节点,无法进行交换

代码思路:

这里使用了个trick,直接使用self代替了新的空节点,只要带有next就好,没什么差别,a代表前一个结点,b代表后一个结点,然后替换结点,更新pre结点到交换后的位置,继续判断。返回空节点的next就是交换后的链表。

  • 看图说话(自己画的):
    在这里插入图片描述

代码:

def swapPairs(self,head):
	pre,pre.next = self,head
	while pre.next and pre.next.next:
		a = pre.next
		b = a.next
		pre.next,b.next,a.next = b,a,b.next
		pre = a  #更新pre指针
	return self.next

复 杂 度 分 析 : \color{red}{复杂度分析:}
时间复杂度为O(n),空间复杂度为O(1)

递归做法

解题思路:还是交换两个点,本节点和它的next结点,用上面的图解释,假如只有三个结点[a,b,c],a就是head,b是next_node
head.next = self.swapPairs(next_node.next) 这一句就是a指向c(上图的第三步),因为c后面是None,函数传入了next_node.next即c,所以函数直接返回的是c,next_node.next = head就是b指向a,这样就是b->a->c啦!

class Solution(object):
    def swapPairs(self, head: ListNode) -> ListNode:
        """
        :type head: ListNode
        :rtype: ListNode
        """
        #终止条件
        if head == None or head.next==None:
        	return head
        #被交换的两个点是head和next_node
        next_node = head.next  #第二个结点
		#交换过程
		head.next = self.swapPairs(next_node.next) 
		next_node.next = head
		#现在的head是second_node
		return next_node 

复 杂 度 分 析 : \color{red}{复杂度分析:}
时间复杂度为O(n),空间复杂度为O(n)

leetcode141.环形链表(判断是否有环)

示例:使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。如果有环,pos的值为环所在的结点

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
在这里插入图片描述
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
在这里插入图片描述

  • 解题思路:快慢指针法。快指针走两步,慢指针走一步,如果有环总会遇到的。
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None
        
class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        if not head:
            return head
        slow=fast=head
        while slow and fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow is fast :
                return True
        return False

a = ListNode(1)
b = ListNode(2)
c = ListNode(31)
d = ListNode(4)
a.next =b
b.next =c 
c.next = d
d.next = b
s = Solution()
x = s.hasCycle(a)
print(x)

复 杂 度 分 析 : \color{red}{复杂度分析:}
时间复杂度为O(n),
空间复杂度:我们只使用了慢指针和快指针两个结点,所以空间复杂度为 O(1)

暴力破解法

通常人是用比较暴力的思维,读取整个链表,然后放进一些容器中,例如列表、字典、哈希表,然后判断是否有重复值,就知道有没有环了。

  • 解题思路:这里推荐使用Set(集合),因为比较快,为什么?set去重有两个函数:hash和eq;当两个变量的hash值不同则认定为不相同,若哈希值一样,调用eq函数,当返回True则认为相同,应该去除其中一个变量
class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        id_list = set()
        if not head: return False
        while head.next:
            if head in id_list: return True
            id_list.add(head)
            head = head.next
        return False

复 杂 度 分 析 : \color{red}{复杂度分析:}
时间复杂度:O(n)对于含有 n 个元素的链表,我们访问每个元素最多一次。添加一个结点到哈希表中只需要花费 O(1)的时间。
空间复杂度:O(n),空间取决于添加到哈希表中的元素数目,最多可以添加 n个元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值