当前位置: 首页 > article >正文

力扣第 61 题旋转链表

题目描述

给定一个链表,旋转链表,将链表中的每个节点向右移动 k k k 个位置,其中 k k k 是非负数。

示例 1:

输入: head = [1,2,3,4,5], k = 2
输出: [4,5,1,2,3]
解释:
向右旋转 1 步: [5,1,2,3,4]
向右旋转 2 步: [4,5,1,2,3]

示例 2:

输入: head = [0,1,2], k = 4
输出: [2,0,1]
解释:
向右旋转 1 步: [2,0,1]
向右旋转 2 步: [1,2,0]
向右旋转 3 步: [0,1,2]
向右旋转 4 步: [2,0,1]

约束:

  • 链表中的节点数在范围 [ 0 , 500 ] [0, 500] [0,500] 内。
  • − 100 ≤ N o d e . v a l ≤ 100 -100 \leq Node.val \leq 100 100Node.val100
  • 0 ≤ k ≤ 2 ∗ 1 0 9 0 \leq k \leq 2 * 10^9 0k2109

解题思路

  1. 特殊情况处理:

    • 如果链表为空或只有一个节点,或者 k = 0 k = 0 k=0,直接返回原链表。
  2. 计算链表长度:

    • 遍历链表,计算链表长度 n n n
  3. 优化旋转步数:

    • 由于旋转 k k k 次相当于旋转 k % n k \% n k%n 次,减少多余计算。
  4. 找到旋转点:

    • 新的头节点的位置是 n − ( k % n ) n - (k \% n) n(k%n)。需要找到链表中对应的位置,将链表断开并重新连接。
  5. 形成环再断开:

    • 可以将链表连成环,然后在适当位置断开。

C 代码实现

以下是基于上述思路的 C 语言实现:

#include <stdio.h>
#include <stdlib.h>

// 定义链表节点结构
struct ListNode {
    int val;
    struct ListNode *next;
};

// 旋转链表函数
struct ListNode* rotateRight(struct ListNode* head, int k) {
    if (!head || !head->next || k == 0) {
        return head; // 特殊情况直接返回
    }

    // 计算链表长度
    int n = 1;
    struct ListNode *tail = head;
    while (tail->next) {
        tail = tail->next;
        n++;
    }

    // 优化 k,计算实际旋转步数
    k = k % n;
    if (k == 0) {
        return head; // 如果 k 为 0,不需要旋转
    }

    // 将链表连成环
    tail->next = head;

    // 找到新头节点和新尾节点
    int stepsToNewHead = n - k;
    struct ListNode *newTail = head;
    for (int i = 1; i < stepsToNewHead; i++) {
        newTail = newTail->next;
    }
    struct ListNode *newHead = newTail->next;

    // 断开环
    newTail->next = NULL;

    return newHead;
}

// 辅助函数:创建新节点
struct ListNode* createNode(int val) {
    struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode->val = val;
    newNode->next = NULL;
    return newNode;
}

// 辅助函数:打印链表
void printList(struct ListNode* head) {
    while (head) {
        printf("%d -> ", head->val);
        head = head->next;
    }
    printf("NULL\n");
}

// 主函数测试
int main() {
    // 创建链表 [1, 2, 3, 4, 5]
    struct ListNode *head = createNode(1);
    head->next = createNode(2);
    head->next->next = createNode(3);
    head->next->next->next = createNode(4);
    head->next->next->next->next = createNode(5);

    printf("原始链表: ");
    printList(head);

    int k = 2;
    struct ListNode *rotated = rotateRight(head, k);

    printf("旋转链表后: ");
    printList(rotated);

    return 0;
}

代码解析

  1. 特殊情况处理:

    • 如果链表为空、只有一个节点,或者 k = 0 k = 0 k=0,直接返回原链表,避免无意义操作。
  2. 链表长度计算:

    • 遍历链表,记录长度 n n n 并找到尾节点 tail
  3. 优化旋转步数:

    • 使用 k % n k \% n k%n 计算有效旋转次数。如果结果为 0,说明无需旋转。
  4. 形成环并找到新头:

    • 将链表尾节点连接到头节点,形成环。
    • 根据 stepsToNewHead 找到新尾节点 newTail,然后确定新头节点 newHead
  5. 断开环:

    • newTail->next 设置为 NULL,完成旋转。

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)
    • 遍历链表计算长度需要 O ( n ) O(n) O(n)
    • 找到新头节点需要 O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
    • 只使用了常量级的额外空间。

测试结果

输入:

head = [1,2,3,4,5], k = 2

输出:

旋转链表后: 4 -> 5 -> 1 -> 2 -> 3 -> NULL

http://www.kler.cn/a/407383.html

相关文章:

  • LeetCode题解:28.找出字符串中第一个匹配项的下标【Python题解超详细,滑动窗口法、内置 find 函数、KMP算法】,知识拓展, KMP算法
  • Java与Kotlin在鸿蒙中的地位
  • HAProxy面试题及参考答案(精选80道面试题)
  • 文件管理 IV(文件系统)
  • 快速入门消息队列MQ、RabbitMQ
  • 19.QT程序简单的运行脚本
  • 【最优清零方案——贪心+滑动窗口+线段树】
  • TIM输入捕获
  • 网页F12:缓存的使用(设值、取值、删除)
  • 远程控制软件使用教程
  • 使用bcc/memleak定位C/C++应用的内存泄露问题
  • uni-app打包H5自定义微信分享
  • 【eNSP】动态路由协议RIP和OSPF
  • [JLOI2014] 松鼠的新家(重链剖分+线段树)
  • Python完成达梦数据库备注到MySQL数据备注的脚本
  • 探索 .NET 9 控制台应用中的 LiteDB 异步 CRUD 操作
  • 141. Sprite标签(Canvas作为贴图)
  • 大数据新视界 -- 大数据大厂之 Impala 性能优化:融合人工智能预测的资源预分配秘籍(上)(29 / 30)
  • 电子应用设计方案-19:智能云饭锅系统方案设计
  • 039_SettingsGroup_in_Matlab图形界面的设置选项