LeetCode题练习与总结:旋转链表--61

301 篇文章 0 订阅
177 篇文章 0 订阅

一、题目描述

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

示例 1:

输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]

示例 2:

输入:head = [0,1,2], k = 4
输出:[2,0,1]

提示:

  • 链表中节点的数目在范围 [0, 500]
  • -100 <= Node.val <= 100
  • 0 <= k <= 2 * 10^9

二、解题思路

  1. 确定链表的长度:首先,我们需要确定链表的长度。这可以通过遍历链表并计数节点来完成。得到链表长度后,我们可以对 k 进行取模操作,因为如果 k 大于链表的长度,旋转的效果与旋转 k 模链表长度是相同的。

  2. 连接链表尾部到头部:找到链表的尾节点(即最后一个节点),并将尾节点的 next 指向头节点,从而形成一个环形链表。

  3. 找到新的尾节点:我们需要找到新的尾节点,即原链表的第 (length - k) 个节点。我们可以通过从头部开始的指针遍历链表来找到这个节点。

  4. 更新头节点和尾节点:将新找到的尾节点的 next 置为 null,这样就将环形链表断开,形成原始的非环形链表。此时,新尾节点的前一个节点就是新的头节点。

  5. 返回新的头节点

三、具体代码

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if (head == null || head.next == null) {
            return head;
        }

        // Step 1: Find the length of the linked list
        ListNode current = head;
        int length = 1;
        while (current.next != null) {
            current = current.next;
            length++;
        }

        // Step 2: Connect the end of the list to the head (make a circular list)
        current.next = head;

        // Step 3: Find the new tail node (the (length - k)th node from the beginning)
        // and also find the new head node
        current = head;
        k = k % length; // In case k is larger than the list length
        for (int i = 0; i < length - k - 1; i++) {
            current = current.next;
        }

        // Step 4: Update the new head and tail nodes
        ListNode newHead = current.next;
        current.next = null;

        // Step 5: Return the new head of the list
        return newHead;
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 寻找链表长度:这部分代码需要遍历整个链表,因此时间复杂度是 O(n),其中 n 是链表的节点数。
  • 连接链表形成环形:这一步仅仅是将链表的尾节点指向头节点,时间复杂度是 O(1)。
  • 找到新的头节点和尾节点:我们需要找到第 (length - k) 个节点,这需要遍历链表,时间复杂度是 O(n)。
  • 更新头尾节点:这一步也是常数时间操作,时间复杂度是 O(1)。
  • 综上所述,主要的时间消耗在寻找链表长度和找到新的头节点这两个步骤,因此总的时间复杂度是 O(n)。
2. 空间复杂度
  • 代码中使用了常数个额外空间,即一些指针变量(如 currentnewHead),以及一个整数变量 lengthk
  • 由于没有使用任何与输入链表大小成比例的数据结构,所以空间复杂度是 O(1)。

五、总结知识点

  1. 链表数据结构:链表是一种线性数据结构,其中的每个节点包含数据和指向下一个节点的指针。在这个问题中,使用了单链表,每个 ListNode 包含 val(存储数据)和 next(指向下一个节点的指针)。

  2. 遍历链表:代码中的 while 循环用于遍历链表以确定链表的长度。这是处理链表时常见的操作,需要一直遍历直到链表的尾部。

  3. 链表的尾递归:为了创建一个环形链表,代码中将链表的尾节点的 next 指针指向了头节点。这是实现链表旋转的关键步骤。

  4. 取模运算:在进行链表旋转时,k 可能大于链表的长度。使用 k = k % length; 可以确保旋转的有效次数不会超过链表的长度,这是一种常见的优化手段。

  5. 指针操作:代码中通过指针操作来找到新的头节点和尾节点。在链表中,指针操作是非常关键的技能,因为它允许我们在不使用额外空间的情况下修改链表的结构。

  6. 断开链表:为了完成链表的旋转,需要将环形链表断开,这通过将尾节点的 next 指针设置为 null 来实现。

  7. 边界条件:代码在开始时检查了链表是否为空或只有一个节点,这是处理链表问题时常见的边界条件检查,确保了算法的健壮性。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直学习永不止步

谢谢您的鼓励,我会再接再厉的!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值