【LeetCode刷题记录】单链表难点总结及Python代码实现

不时记录一下自己刷题的想法,以免后续遗忘,所有的代码都是用Python写的,因为日后需要,尽量所有代码都用Python写了,单链表的应该没有特别大的难度的东西了,有几道题写了测试的代码,应该都能看出来哈,没有加图解,对找环不清楚的,可以去看看知乎

1、链表的翻转

【leetcode 206】

我最先想到的办法就是利用头插法,重新构造一个链表,但这样势必会增加空间复杂度

最不费时间复杂度的方法,就是利用双指针法指针就行修改就行了。。。。。双指针法的时候要注意一下改变之后,率先移动的是后面的指针,而不是前面的指针,否则pre会迷失自己的方向。。。。。。

# Definition for singly-linked list.
# 最简单的思路,找到尾节点
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
class Solution:
    def reverseList(self, head):
        new_head = ListNode(val=-1 , next=None) # 假设出一个哨兵节点
        cur = head
        while cur:
            tmp = ListNode(val=cur.val,next=new_head.next) # 注意了,python中等于号相当于起了一个别名!!!不申请新空间就出问题可还行
            # tmp = cur # 这么写的话,两个指针指的是一个东西,烦死了
            # tmp.next = new_head
            new_head.next = tmp
            cur = cur.next
        return new_head.next


L5 = ListNode(5,None)
L4 = ListNode(4,L5)
L3 = ListNode(3,L4)
L2 = ListNode(2,L3)
L1 = ListNode(1,L2)

s =Solution()
res = s.reverseList(L1)
while res:
    print(res.val)
    res = res.next

2、链表找交点

【leetcode 160】

这个我之前没有推理过,加入过两个链表相交

两个链表相交的情况:

1 a+b

2 c + b

那么当一个链表走到结尾的时候移动到另一个链表的表头就好了,保证他们两者走的路径都是a+b+c。即便两个链表的长度一样也没关系,如果一样的话,那更容易,只要两个指的是同一个点就退出循环了呗。

两个链表不相交的情况:

  • 链表长度相同,两个链表同时走到终点,终点的值不相同,注定他俩是没有交点的

  • 链表长度不同,两个链表也是会同时走到终点的,因为都走了m+n的路径,直接返回None就好了

# Definition for singly-linked list.
# 内存中指向的是同一个位置的才是交点,仅仅是数值相同的话,不算是交点的
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode):
        if  not headA or not headB: # 有一个链表为空的话,就返回空置
            return None
        h_a = headA
        h_b = headB
        while h_a!= h_b: # 两者要是不相交,并且相等的话,一定最后会有返回值的,一定保证每一个都走了 a+b+c的距离
            if h_a.next == None and h_b.next == None: # 到达链表尾部了
                return None # 两者同时到达终点的情况 只有两种可能,一种是链表长度相等,一种是二者根本不相交,无论哪一种,都是不相交                
            elif h_b.next == None:
                h_b = headA
                h_a = h_a.next
            elif h_a.next == None:
                h_a = headB
                h_b = h_b.next
            else:
                h_a = h_a.next
                h_b = h_b.next
        
        return h_a
    

3、判断链表是否有环,并且找到环的位置

【leetcode 142】

快慢指针的想法,快指针一次走两步,慢指针一次走一步,快指针如果走向了空,那么就说明没有环(但是要注意的一点是,快指针每走一步走要判断一下是不是空,要不然直接走两步会出现None.next的情况

如果要是相遇了的话,就证明有环,同时将快指针移动至链表的头部,之后快慢指针都一次走一步,这样会在环的入口处相遇,证明过程自己画一个图就很好理解的。核心思想就是快指针走的路途是慢指针的二倍,利用这个等式就可以得出,最终两个指针分在相遇点和起点出发,最终一定会在环的入口相遇的。不明白的一定一定自己画一个图,立马就明白了

# Definition for singly-linked list.
# 判断两个链表是否有环,有环的话,需要找到环的位置
# 双指针的思想,快指针先走,每次走两步,如果走的时候就遇见了None,则说明这个链表没有环
# 如果快指针和慢指针相遇了,则记录一下相遇的那一个点,两个指针一个回到表头,一个接着从这里走
# 再次相遇的时候就是,就是环的入口的位置
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    def detectCycle(self, head):
        if not head: # 没有节点的情况
            return None
        fast = head  # 都从表头开始走
        slow = head
        count = 0  # 第一次最开始的时候指定都指向了一个点,所以要处理一下第一次的点
        while True:
            if fast.next!=None:
                fast = fast.next
                if fast.next!=None:
                    fast = fast.next
                else:
                    return None # 不能走两步
            else:
                return None # 甚至fast下一步都没有
            slow = slow.next
            if slow == fast:
                break
        # 到这里slow和fast已经相遇了
        fast = head
        while slow != fast:
            fast = fast.next
            slow = slow.next    
        return slow # 这就是最后相遇的点

4、删除倒数第n个节点

【leetcode 19】

也采用双指针的思想就好了,快指针先进行移动,慢指针在快指针走了n-1步之后同时进行移动,这样快指针走到终点的时候,慢指针也恰好移动至倒数第n个位置了

# Definition for singly-linked list.
# 删除倒数第n个节点,只要等到出发了n个之后再出发就好了,不保存前一个指针,直接交换值
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
class Solution:
    def removeNthFromEnd(self, head, n):
        count = 0
        h = ListNode(-1,head)
        cur = head
        prr = h
        pr = head
        while cur.next: # 一定要注意这里,如果不是next的话,会多移动一次,造成pr指的是cur,prr指的是应该被删除的元素
            count += 1
            if count >= n: # 检查一下这里是不是对的
                pr = pr.next
                prr = prr.next
            cur = cur.next
        # 找到之后,有可能删除最后一个节点
        prr.next = pr.next
        return h.next

L5 = ListNode(5,None)
L4 = ListNode(4,L5)       
L3 = ListNode(3,L4)       
L2 = ListNode(2,L3)      
L1 = ListNode(1,L2)  

s = Solution()
res = s.removeNthFromEnd(L1,2)
while res:
    print(res.val)
    res = res.next
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值