算法训练营day4

目录

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

19.删除链表的倒数第N个节点

面试题 02.07. 链表相交

142.环形链表II


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

用虚拟头结点,这样会方便很多。

本题链表操作就比较复杂了,建议大家先看视频,视频里我讲解了注意事项,为什么需要temp保存临时节点。

题目链接/文章讲解/视频讲解: 代码随想录

方法一:递归法

def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None or head.next is None:
            return head
        
        pre = head
        cur = head.next
        next = head.next.next
        
        cur.next = pre
        pre.next = self.swapPairs(next)
        return cur

方法二:循环法

自己写的代码:

def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        
        if (not head):
            return None
        if (not head.next):
            return head
        dummy = ListNode(next=head)
        pre = dummy
        cur = head

        while(cur and cur.next):
            nxt = cur.next
            print('nxt:', nxt)
            pre.next = nxt 
            cur.next = nxt.next 
            nxt.next = cur 
            pre = cur
            cur = cur.next
        return dummy.next

代码随想录的代码:

cur从虚拟节点开始,循环条件判断为cur.next and cur.next.next, 用临时节点保存值,保存cur.next 和cur.next.next, 本质逻辑是一样的,但是代码逻辑更顺畅一些,不需要思考太多。迭代cur使用cur = cur.next.next

重点参考如下图即可

def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        
        dummy_head = ListNode(next = head)
        current = dummy_head

        while current.next and current.next.next:
            temp = current.next
            temp1 = current.next.next.next

            current.next = current.next.next
            current.next.next = temp
            temp.next = temp1
            current = current.next.next
        return dummy_head.next

19.删除链表的倒数第N个节点

双指针的操作,要注意,删除第N个节点,那么我们当前遍历的指针一定要指向 第N个节点的前一个节点,建议先看视频。

题目链接/文章讲解/视频讲解:代码随想录

力扣链接

第一想法:使用双指针法获得链表的长度,减去n后得到倒数第n个节点的位置,计算链表的长度废了一些功夫

def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        fast = head
        slow = head
        dummy = ListNode(next = head)
        if not (head):
            return None
        length = 0
        while(fast and fast.next):
            slow = slow.next
            fast = fast.next.next
            length += 1
        if fast:
            length = length*2 + 1
        else:
            length = length*2
        pre = dummy
        for i in range(length - n):
            pre = head
            head = head.next
        pre.next = head.next
        print(head.next)
        return dummy.next

代码随想录解法:

也是快慢指针,但是设定快指针比慢指针快n+1步,这样同时移动时,slow才能指向删除节点的上一节点。

时间复杂度O(n) 空间复杂度 O(1)

dummy_head = ListNode(0, head)

        slow = fast = dummy_head

        for i in range(n+1):
            fast = fast.next
        
        while fast:
            slow = slow.next
            fast = fast.next
        
        slow.next = slow.next.next
        return dummy_head.next

c++代码不一样的点:

1. 头结点的创建

ListNode * dummyHead = new ListNode(0);

2. 判断条件

while(n-- && fast != NULL){

    fast = fast->next
}
fast = fast->next //需要再提前走一步,因为需要让slow指向删除节点的上一个节点

总结:

两种方法

1: 先计算链表长度,再找到要删除的点的前一个节点

2. 快慢指针相差n+1个位置,找到要删除的点的前一个节点。时间复杂度O(n) 空间复杂度 O(1)

面试题 02.07. 链表相交

本题没有视频讲解,大家注意 数值相同,不代表指针相同。

力扣链接

题目链接/文章讲解:代码随想录

一开始没什么思路,看了代码随想录

方法1:先求出两个链表各自的长度,求出链表长度的差值,然后让curA移动到curB末尾对齐的位置,则后续如果两个值相同,则为交点。

方法2:两个链表都遍历一遍,走一圈之后会到达交点(这个方法之前看过,后来又忘记了)

def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if not headA or not headB:
            return None
        
        pointerA = headA
        pointerB = headB 

        while pointerA != pointerB:
            pointerA = pointerA.next if pointerA else headB
            pointerB = pointerB.next if pointerB else headA
        
        return pointerA

142.环形链表II

算是链表比较有难度的题目,需要多花点时间理解 确定环和找环入口,建议先看视频。

力扣链接

题目链接/文章讲解/视频讲解:代码随想录

使用快慢指针法,当两个指针相遇的时候,slow走过的节点数为(x+y), fast走过的节点数:

x + y + n (y + z)

2 * ( x + y ) = x + y + n (y + z)

两边消除(x+y)得到:

 x + y = n (y + z)\\ x = n (y + z) - y\\ x = (n-1)(y+z) + z

当n是1时,x = z

此时,从头结点和相遇的节点都出发一个指针,当两个指针相遇时,就是环形入口的节点。

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

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        slow = head
        fast = head
        while(fast and fast.next):
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                slow = head
                while slow != fast:
                    slow = slow.next
                    fast = fast.next
                return slow
        return None

写过好几遍的题目一直记不住,本质还是没有理解到位

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
邓俊辉教授是计算机科学与技术领域著名的教育家和研究者。他在清华大学担任教授,并负责计算机算法与理论方向的研究和教学工作。邓俊辉教授是中国计算机学会副理事长、国际著名科技出版社Springer中国系列丛书主编、IEICE China Communications主编、Journal of Internet Technology编委、《数据结构与算法教程》作者等。 在邓俊辉教授的指导下,他办了多次Dijkstra算法训练营,旨在培养学生对于算法学习的兴趣与能力。Dijkstra算法是一种用于图论中求解最短路径问题的经典算法,具有广泛的应用领域,如路由算法、网络规划和GPS导航系统等。在训练营中,邓俊辉教授通过讲解算法的原理和思想,引导学生进行编程实践和案例分析,帮助他们深入理解Dijkstra算法的应用场景与实际解决问题的能力。 邓俊辉教授所组织的Dijkstra算法训练营受到了广大学生的欢迎和积极参与。通过训练营的学习,学生不仅可以掌握Dijkstra算法的具体实现过程,还能了解算法设计的思路和应用的局限性。在训练营中,学生还可以与同学们进行交流和合作,共同解决实际问题,促进彼此的学术成长和人际交往能力的培养。 总之,邓俊辉的Dijkstra算法训练营为学生提供了一个系统、全面学习算法知识的平台,帮助他们培养解决实际问题的能力和思维方式。通过这样的培训,学生不仅能在学术领域取得更好的成绩,还可以为将来的职业发展打下坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值