关于旋转链表的OJ题的一些总结

Posted 正义的伙伴啊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于旋转链表的OJ题的一些总结相关的知识,希望对你有一定的参考价值。

旋转链表OJ题

引入问题

原题链接

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

解法一

刚开始做这题我用的是最铸币的方法,也是最容易想到的方法,多指针方法,然后通过循环遍历整个链表,这里的循环条件使n3不为NULL

设置4个指针分别指向要交换的两个节点和下一个要交换的两个节点

接下来这部就是进行交换,但是注意n1要指向n3,因为n3是下一个交换过后的头节点

然后就要进行一个指针的自增,但是自增的过程中又会出现两种情况的尾巴

  1. 节点是奇数个
    我的处理方法是p和n3分别向后移动两个使p为多出来的节点,n3为空节点
  2. 节点是偶数个
    我的处理方法是p向后移动两位,n3先后移动一位指向空节点

这样处理的结果就是:出循环在把n2的下一个节点指向n1,n1的下一个节点指向p,这里p就包含了奇数和偶数的两种尾巴
最后返回Newhead就结束了
但是这里还要注意两种特殊情况:

  1. 输入的是空指针
  2. 定义的时候要判断节点数是不是大于4个节点

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* swapPairs(struct ListNode* head){
    if(head==NULL || head->next==NULL)
    return head;
    struct ListNode *newhead=head->next;
    struct ListNode*n1=head;
    struct ListNode*n2=head->next;
    struct ListNode*p=n2->next;
     struct ListNode*n3=NULL;
    if(p==NULL)
    n3=NULL;
    else
    n3=n2->next->next;
    while(n3)
    {
        n2->next=n1;
        n1->next=n3;
        n1=p;
        n2=n3;
        if(n3->next)
        {
            n3=n3->next->next;
        }
        else
        {
             n3=n3->next;
        }
        p=p->next->next;
    }
    n2->next=n1;
    n1->next=p;
    return newhead;

}

解法二(简化)

但是这种方法并不是最优的解法,下面介绍一下递归法
我们发现其实我们实现的内容是重复的,这就可以用递归的思想

传过来的头节点前两个进行交换,返回交换后的头节点地址,并把第三个节点传给函数,当作下次递归的头节点。

递归结束的条件就是节点数小于2

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* swapPairs(struct ListNode* head){
    struct ListNode*n1=head;
    if((n1==NULL) || (n1->next==NULL))
    return n1;
    struct ListNode*n2=head->next;
    struct ListNode*n3=n2->next;
    n2->next=n1;
    n1->next=swapPairs(n3);
    return n2;

}

这种方法就比第一种简洁多了

问题提升

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
进阶:
你可以设计一个只使用常数额外空间的算法来解决此问题吗?
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

原题

这个问题就是上一个问题的升级版
首先我们要找到进入递归的条件:链表的节点数要大于k


我们先遍历一遍数组并找到第K+1个节点的地址Next(下一次递归的头节点),并开始循环,循环结束的条件是n3!=Next

循环结束将n2的下一个节点指向n1

进入下一次递归

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* reverseKGroup(struct ListNode* head, int k){
    if(k<=1)
    return head;
    int size=0;
    struct ListNode*p=head;
    struct ListNode*NEXT=NULL;
    while(p)
    {
        if(size==k)
        NEXT=p;
        p=p->next;
        size++;
    }
    if(size<k)
    return head;
    else
    {
        struct ListNode*n3=head->next->next;
        struct ListNode*n2=head->next;
        struct ListNode*n1=head;
        while(n3!=NEXT)
        {
            n2->next=n1;
            n1=n2;
            n2=n3;
            n3=n3->next;
        }
        n2->next=n1;
        head->next=reverseKGroup(NEXT,k);
         return n2;
    }

}

欢迎大家提供不同的想法!

以上是关于关于旋转链表的OJ题的一些总结的主要内容,如果未能解决你的问题,请参考以下文章

数据结构之超硬核热门复杂度数组链表OJ题2W+文字+图片详解

在IDEA上对链表oj题的测试方法

链表OJ题练习2

数据结构学习笔记(数组链表OJ题)整理与总结

数据结构学习笔记(数组链表OJ题)整理与总结

1024狂欢力扣经典链表OJ题合集