LeetCode-交换链表中节点的问题

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

题目描述:

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
在这里插入图片描述
思路: 首先将整个链表倒置,然后再在倒置后的链表上以两个节点为单位再进行一次倒置。但是这种思路只适用与偶数个节点,如果是奇数个节点,最后一个节点倒置之后,再在倒置后的链表中以两个节点为单位进行倒置会打乱最终的顺序。所以在对链表进行操作之前,首先判断节点个数是否为奇数个。如果是奇数个,那么就将最后一个节点取下保存地址,之后操作完成后,再将该节点拼接到最终链表中。
代码:

class Solution {
	public ListNode swapPairs(ListNode head) {
        int len=0;
        ListNode cur=head,end;
        ListNode temp=new ListNode();
        //链表为空或者只有一个节点直接返回
        if(head==null) {
            return head;
        }
        if(head.next==null) {
            return head;
        }
        //遍历获得链表长度并保存最后一个节点的前一个节点地址
        while(cur.next.next!=null) {
            len++;
            cur=cur.next;
        }
        //判断节点数是否为奇数个
        if((len+2)%2!=0) {
        	//奇数个切断最后一个节点并保存地址以便之后拼接
            end=cur.next;
            cur.next=null;
        } else {
            end=null;
        }
        //倒置整个链表
        head=reverse(head);
        //记录最终链表尾巴位置方便之后拼接
        ListNode tail=head.next;
        //以两个节点为单位倒置头插
        while(head!=null) {
            ListNode hNext=head.next.next;
            ListNode headNext=head.next;
            headNext.next=temp.next;
            temp.next=head;
            head=hNext;
        }
        //拼接
        tail.next=end;
        return temp.next;

    }
	
	//链表倒置
    public ListNode reverse(ListNode head) {
        ListNode temp=new ListNode();
        while ( head != null ) {
            ListNode headNext=head.next;
            head.next=temp.next;
            temp.next=head;
            head=headNext;
        }
        return temp.next;
    }
}

2.K 个一组翻转链表

题目描述:

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

在这里插入图片描述
思路: 看到这题我就想到我前面的两两交换链表节点的做法。首先遍历链表记录长度,判断长度与k是否为整数倍关系,如果不是就要进行取模运算得到余数,并通过findNode函数得到倒数余数个点的地址以及倒数余数加一个点的地址,从倒数余数个点处断开链表,之后完成操作后再拼接。反转断开后的链表,并按照k个一组的方式来进行头插,在头插之前会先定义一个头节点来方便后续插入。在之后的循环中,head用来记录每一个k组的第一个元素地址,nextPre来记录每一个k组的最后一个元素的地址,Next来记录下一个k组的第一个元素的地址,nextPre和Next都通过cur接收head地址值之后遍历k-1次获取,然后头插的操作相当于再次逆置链表,只不过是以k个元素为一组的。完成外部循环后,链表拼接上之前断开的一部分即可。这种方法虽然能运行成功,但是效率比较低,代码冗长,自己钻牛角尖写出来的。

代码:

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head==null) {
            return null;
        }
        ListNode cur=head;
        int len=0;
        //得到链表长度
        while(cur!=null) {
            cur=cur.next;
            len++;
        }
        //链表长度等于k直接逆置返回
        if(len==k) {
            return reverse(head);
        }
        ListNode endPre;
        ListNode end;
        //链表长度不等于k的倍数
        if(len%k!=0) {
        	
        	//记录倒数第k+1个节点位置,方便之后断开操作
            endPre=findNode(head,len%k+1);
            //记录倒数第k个节点位置
            end=findNode(head,len%k);
            //断开后面的节点
            endPre.next=null;
            
        } else {
        //链表长度是k的倍数,则不需要断开
            end=null;
            endPre=null;
        }
        //反转剩余的链表
        head=reverse(head);
        //记录反转后头的位置,在最终链表中改位置为最后一个k组的第一个元素位置
        ListNode tail=head;
        int count=k-1;
        while(count!=0) {
        //通过遍历得到最终返回链表的最后一个k组的最后一个元素的地址
            tail=tail.next;
            count--;
        }
        ListNode temp=new ListNode(-1);
        ListNode Next=null;
        ListNode nextPre=null;
        cur=head;
        int tmp=0;
        while(head!=null) {
            tmp=k-1;
            while(tmp!=0) {
                cur=cur.next;
                tmp=tmp-1;
            }
            //通过循环得到上一个k组最后一个元素地址
            nextPre=cur;
            //这一个k组的第一个元素地址
            Next=cur.next;
            //头插操作
            nextPre.next=temp.next;
            temp.next=head;
            //更新
            head=Next;
            cur=Next;

        }
        //通过之前记录的最后一个k组的最后一个元素的地址完成拼接
        tail.next=end;
        return temp.next;
       
    }
//逆置链表
    public ListNode reverse(ListNode head) {
        ListNode temp=new ListNode(-1);
    
        while(head!=null) {
            ListNode headNext=head.next;
            head.next=temp.next;
            temp.next=head;
            head=headNext;
        }
        return temp.next;
    }

//找出倒数第k个节点
    public ListNode findNode(ListNode head,int k) {
        if(head==null) {
            return null;
        }
        ListNode fast=head;
        ListNode slow=head;
        while(k!=1) {
            fast=fast.next;
            k=k-1;
        }

        while(fast.next!=null) {
            fast=fast.next;
            slow=slow.next;
        }
        return slow;
    }

}
  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值