leetcode 25.k个一组翻转链表

思路:模拟

这道题其实不难在算法,因为这道题根本就没有所谓的算法,而只有所谓的模拟和代码能力的体现。

我们看题目,说是k个一组进行翻转,但是不足k个的那一组的顺序保持不变。如果我们选择一个一个的翻转,那么,当我们并不知道是不是在不足k个那一组的时候就进行了翻转,导致我们的顺序失调。因为链表本身就是不知道长度的。所以我们不能挨个去翻转,而是选择一组一组去翻转。

但是怎么翻转呢?我们首先需要知道链表的总长度,这样我们才能知道到底有多少组k个元素。所以我们需要首先把链表遍历一遍,然后我们求出来长度。这里的长度用处就是用来计算有多少组的,所以可以len%k求余,之后用(len-len%k)/k就是有多少组。这里作者没用,直接计数器满足count==len-len%k,其实是等价的。

这里需要几个特判:

1.如果链表本身就是空的,那么就直接null;

2.如果链表的长度并不足k个一组,那么直接返回原来的链表即可;

3.如果k==1,也没有翻转的必要,还是返回原来的链表。

好了,解决这些特殊因素之后,我们开始模拟:

我们会发现,如果只在原链表上不好改地址,这里作者投机取巧定义了一个栈。为什么用栈呢?先进后出,我们可以用这个特点来翻转,先出来的元素肯定翻转之后链表的头,最后的当然就是尾了。但是我们这里是k个一组,所以并不能下定结论这一组就是第一组,并且尾的指向并不明,因为下一组还没有进行翻转,所以我们又定义了一个集合list,只用来存储头和尾(存储的顺序不能颠倒),这样可以保证集合的长度是偶数,并能够有序的取出并修改指针。

定义指针指向原来链表,指到一个结点就count++,如果count不满足count%k==0,那么入栈。满足,我们就开始处理。用出栈的元素指向栈顶的元素,就相当于是翻转了。之后再进行更新,再这样操作......

然后,当我们count==len-len%k的时候,也就是到最后一组未翻转前的尾元素时,我们需要记录它的下一个元素,因为它的下一个元素那一组是不足k个的一组,所以我们需要知道它的第一个结点,之后修改指针用来指向它。

之后,我们在集合list中遍历,注意,是从第一组翻转后的尾元素开始,也就是下标为1,指向它的下一个元素,也就是第二组翻转后的头元素。依次类推...最后一组翻转后的尾元素就指向我们刚刚存储的不足k个元素的那一组的头元素,最后返回集合的0下标元素,即第一组翻转后的头元素就行了。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head==null)
        return null;
        int len=0;
        ListNode tmpp=head;
        while(tmpp!=null){
            len++;
            tmpp=tmpp.next;
        }
        if(len<k||k==1)
        return head;
        List<ListNode>list=new ArrayList<ListNode>();
        Deque<ListNode>stk=new LinkedList<ListNode>();
        ListNode cnt=head;
        int count=0;
        int cha=len%k;
        ListNode cao=new ListNode(-1);
        while(cnt!=null&&count<len-cha){
            count++;
            ListNode cnt_next=cnt.next;
            if(count%k!=0){
            stk.push(cnt);
            }
            else{
                if(count==len-cha){
                    cao=cnt_next;
                }
                if(!stk.isEmpty()){
                    ListNode ha=cnt;
                    ha.next=stk.peek();
                    list.add(ha);
                }
                while(!stk.isEmpty()){
                    ListNode tem=stk.pop();
                    if(stk.peek()!=null)
                    tem.next=stk.peek();
                    else
                    {
                        tem.next=null;
                        ListNode tail=tem;
                        list.add(tail);
                    }
                }
            }
            cnt=cnt_next;
        }
        for(int i=1;i<list.size();i+=2){
            if(i+1>=list.size())
            break;
            else{
             ListNode tmp1=list.get(i);
             ListNode tmp2=list.get(i+1);
             tmp1.next=tmp2;
            }
        }
        ListNode res=list.get(list.size()-1);
        res.next=cao;
        ListNode nows=list.get(0);
        return nows;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值