【算法面试必刷JAVA版三】链表中的节点每k个一组翻转

盲目刷题,浪费大量时间,博主这里推荐一个面试必刷算法题库,刷完足够面试了。传送门:牛客网面试必刷TOP101

🏄🏻作者简介:CSDN博客专家,华为云云享专家,阿里云专家博主,疯狂coding的普通码农一枚

    

🚴🏻‍♂️个人主页:莫逸风

    

👨🏻‍💻专栏题目地址👉🏻牛客网面试必刷TOP101👈🏻

    

🇨🇳喜欢文章欢迎大家👍🏻点赞🙏🏻关注⭐️收藏📄评论↗️转发

alt

题目:链表中的节点每k个一组翻转

描述:

将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表
如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。

数据范围:0≤n≤2000 , 1≤k≤2000 ,链表中每个元素都满足 0≤val≤1000
要求空间复杂度 O(1),时间复杂度 O(n)

例如:

给定的链表是 1→2→3→4→5

对于 k = 2k=2 , 你应该返回 2→1→4→3→5

对于 k = 3k=3 , 你应该返回 3→2→1→4→5

思路:

思路一:堆栈

  1. 不考虑空间问题,队列、栈处理链表太方便了。
  2. 分段入栈。然后取出,注意处理最后一段取队头就好了(我下面代码用的是Deque,java中的双端队列)。

请添加图片描述

思路二:迭代

  1. 和BM02问题相同的处理方式,不过额外处理最后一段比较麻烦。

请添加图片描述

思路三:递归✅

  1. 推荐的处理方式,每次只处理一段,然后递归交给下面处理,本题非常适合用递归。

请添加图片描述

代码:
public class BM03 {

    public static void main(String[] args) {
        ListNode listNode1 = new ListNode(1);
        ListNode listNode2 = new ListNode(3);
        ListNode listNode3 = new ListNode(5);
        ListNode listNode4 = new ListNode(7);
        ListNode listNode5 = new ListNode(9);
        listNode1.next = listNode2;
        listNode2.next = listNode3;
        listNode3.next = listNode4;
        listNode4.next = listNode5;
        ListNode curListNode = listNode1;
        while (curListNode!=null){
            System.out.println(curListNode.val);
            curListNode = curListNode.next;
        }
        curListNode = reverseKGroup3(listNode1,2);
        while (curListNode!=null){
            System.out.println(curListNode.val);
            curListNode = curListNode.next;
        }
    }

    /**
     * 堆栈
     */
    public static ListNode reverseKGroup (ListNode head, int k) {
        // write code here
        ListNode pre = new ListNode(-1);
        ListNode curr = pre;
        pre.next = head;
        Deque<ListNode> deque = new ArrayDeque<>();
        ListNode cur = head;
        int i = 0;
        while (cur!=null){
            i++;
            deque.add(cur);
            cur = cur.next;
            if (i%k==0){
                while (!deque.isEmpty()){
                    curr.next = deque.pollLast();
                    curr = curr.next;
                }
            }
        }
        curr.next = null;
        if (!deque.isEmpty()){
            curr.next = deque.pollFirst();
        }
        return pre.next;
    }

    /**
     * 迭代
     */
    public static ListNode reverseKGroup2 (ListNode head, int k) {
        ListNode pre = new ListNode(-1);
        ListNode result = pre;
        pre.next = head;
        ListNode cur = head;
        ListNode temp;
        int i = 0;
        ListNode next;
        while (cur!=null){
            i++;
            if (i%k==0){
                pre = cur;
                cur = cur.next;
                next = cur;
                // 判断后续是否足够反转
                for (int j = 0; j < k; j++) {
                    if (next == null){
                        return result.next;
                    }
                    next = next.next;
                }
            }else {
                temp = cur.next;
                cur.next = temp.next;
                temp.next = pre.next;
                pre.next = temp;
            }
        }
        return result.next;
    }

    /**
     * 分组递归
     */
    public static ListNode reverseKGroup3(ListNode head, int k) {
        ListNode tail = head; //找到每次翻转的尾部
        for(int i = 0; i < k; i++){ //遍历k次到尾部
            if(tail == null) //如果不足k到了链表尾,直接返回,不翻转
                return head;
            tail = tail.next;
        }
        ListNode pre = null; //翻转时需要的前序和当前节点
        ListNode cur = head;
        while(cur != tail){ //在到达当前段尾节点前
            ListNode temp = cur.next; //翻转
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        head.next = reverseKGroup3(tail, k); //当前尾指向下一段要翻转的链表
        return pre;
    }
}

推荐牛客网面试必刷算法题库,刷完足够面试了。传送门:牛客网面试必刷TOP101

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

莫逸风

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值