算法训练营打卡Day4

题目1.

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

个人认为难点在于理解交换的本质是交换链表中的连接顺序,而不是交换链表的值,因为根据链表的特性这不是合理的做法。

题目链接:. - 力扣(LeetCode)

Python代码:

# Definition for singly-linked list.

# class ListNode(object):

#     def __init__(self, val=0, next=None):

#         self.val = val

#         self.next = next

class Solution(object):

    def swapPairs(self, head):

        """

        :type head: ListNode

        :rtype: ListNode

        """

        #先考虑特殊情况

        #1检查链表是否为空:在Python中,链表是否为空应该检查head是否为None

        if head is None or head.next is None:

            return head

        '''

        2、不直接计算长度,因为这会需要遍历整个链表,

        而题目要求我们在原地修改链表

        '''

        dummy_head = ListNode(next=head)

        #初始化一个指针current,用于遍历链表。

        #开始时,它指向虚拟头部节点。  

        current = dummy_head

        '''

        3、交换节点应该先将current.next的next指向temp

        (即current.next.next.next)

        然后再将current.next的next(原指向current.next.next)指向

        current.next的下一个节点(即current.next自身),

        最后更新current为current.next.next

        '''

        while current.next and current.next.next:  

            #保存要交换的两个节点  

            node1 = current.next      #第一个节点  

            node2 = current.next.next #第二个节点  

            #交换节点连接  

            #node1的next指向node2的next  

            node1.next = node2.next  

            #node2的next指向node1  

            node2.next = node1  

            #current的next指向node2,完成交换  

            current.next = node2  

            #移动current到下一对要交换的节点之前  

            current = node1  

        #返回新的头部节点(跳过虚拟头部节点)  

        return dummy_head.next

C语言代码和思路:

  1. 递归逻辑:

    • 首先,定义一个新的头节点 newHead,它指向原链表的第二个节点(即 head->next)。这是因为我们将要交换 head 和 head->next 的位置,所以新的头节点应该是 head->next

    • 然后,递归地调用 swapPairs 函数处理剩余链表(即从 newHead->next 开始的链表),并将返回的结果设置为 head->next。这里的关键是,递归调用会处理除当前对外的所有节点,并返回新的子链表的头节点。

    • 接下来,将 newHead(即原来的第二个节点)的 next 指针指向 head,完成两个节点的交换。

    • 最后,返回 newHead 作为整个链表新的头节点。

  2. 递归过程:

    • 假设链表为 1 -> 2 -> 3 -> 4,初始调用 swapPairs(1)

    • 在第一次递归中,newHead = 2,然后递归调用 swapPairs(3) 处理剩余链表 3 -> 4

    • 递归调用 swapPairs(3) 会继续这个过程,直到到达基本情况(链表为空或只有一个节点)。

    • 当递归调用返回时,我们开始逐层构建交换后的链表。首先,2 -> 3'(其中 3' 是 3 -> 4 交换后的链表),然后 1 -> 2 -> 3',最终得到 2 -> 1 -> 3' -> 4'(其中 3' 和 4' 是原始 3 -> 4 链表交换后的结果)。

struct ListNode* swapPairs(struct ListNode* head) {

    if(head == NULL) || head->next == NULL){

        return head;

    }

    struct ListNode* newHead = head->next;

    head->next = swapPairs(newHead->next);

    newHead->next = head;

    return newHead;

}

题目2.

19.删除链表中的第N个节点. - 力扣(LeetCode)

考虑使用快慢指针

快指针先行n步,这样快慢指针之间形成了一段长度为n的窗口,之后快慢指针同步向前相当于保持窗口长度不变。这样当快指针到达了末尾指向NULL,另一端的慢指针距离末尾的长度是n,自然就是指向倒数第n个位置了。

为啥快指针先行了n+1步? 由于单链表中的next指针指向的是下一个节点,想要删除倒数第n个节点,自然要将操作指针慢指针指向倒数第n+1个节点,这样才能进行删除操作。 虚拟头节点dummyHead的作用是?

如果单链表中要删除的节点是头节点,这个头节点正好是dummyHead的下一个节点,如此即可统一起来删除操作而不必单独考虑。 额外注意? 如果使用C++,最后记得释放删除的节点以及dummyHead(来自B站评论) https://www.bilibili.com/video/BV1vW4y1U7Gf/?share_source=copy_web&vd_source=1261b97a33f42388f92b473554874c36

class Solution(object):

    def removeNthFromEnd(self, head, n):

        """

        :type head: ListNode

        :type n: int

        :rtype: ListNode

        """

        #考虑使用虚拟头部节点

        #使第n-1个节点指向第n个节点的下一个节点

        '''

        首先让快指针比慢指针先前进n步,然后两个指针同时移动,直到快指针到达链表末尾。

        这时,慢指针就指向了需要删除的节点的前一个节点。但是,这里有一个特殊情况需要注意:如果n等于链表的长度,那么实际上我们要删除的是链表的头节点。因此,我们还需要特别处理这种情况。

# Definition for singly-linked list.

# class ListNode(object):

#     def __init__(self, val=0, next=None):

#         self.val = val

#         self.next = next

class Solution(object):

    def removeNthFromEnd(self, head, n):

        """

        :type head: ListNode

        :type n: int

        :rtype: ListNode

        """

        #考虑使用虚拟头部节点

        #使第n-1个节点指向第n个节点的下一个节点

        '''

        首先让快指针比慢指针先前进n步,然后两个指针同时移动,直到快指针到达链表末尾。

        这时,慢指针就指向了需要删除的节点的前一个节点。但是,这里有一个特殊情况需要注意:如果n等于链表的长度,那么实际上我们要删除的是链表的头节点。因此,我们还需要特别处理这种情况。

        '''

        dummy_head.next = ListNode(next = head)

        prev = dummy_head  # prev用于指向当前要删除节点的前一个节点  

    fast = head  

    # 快指针先前进n步  

    for i in range(n):  

        fast = fast.next

    # 快慢指针同时移动,直到快指针到达末尾  

    while fast:  

        prev = prev.next  

        fast = fast.next  

    # 删除倒数第n个节点  

    prev.next = prev.next.next  

    # 返回虚拟头节点的下一个节点,即原链表的头节点

    return dummy_head.next

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值