算法小练习之每K个一组反转链表

119 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情

1、前言

每天一个算法小练习,本篇使用Java实现。

2、题目描述

给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。

说明:

  • 需要自行定义链表结构,将输入的数据保存到你的链表中;
  • 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换
  • 算法只能使用常数的额外空间。

示例:

输入:
    1 2 3 4 5
    2
输出:
    2 1 4 3 5

3、解题思路

递归实现

这应该是最容易想到的一个解题思路了。

假定K = 2,那么我们需要:

  • 1、选定前两个节点;
  • 2、将前两个节点作为一个链表进行反转;
  • 3、将剩下的链表看作一个新的链表,重复步骤1;

实现代码:

package com.huayi.middleinterface.config;

import java.util.*;


public class ReverseListNode{

    static class ListNode{
        int currVal;
        ListNode next = null;
        ListNode(int val){
            this.currVal = val;
        }
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        String[] inputStrArr = str.split(",");
        ListNode head = new ListNode(-1);
        ListNode rear = head;
        //将输入数据都插入到链表中
        for(String item : inputStrArr) {
            ListNode newNode = new ListNode(Integer.parseInt(item));
            rear.next = newNode;
            rear = newNode;
        }
        int k = sc.nextInt();
        //以K个节点为一组进行反转
        ListNode newHead = reverseK(head.next, k);
        //输出反转后的链表
        ListNode curr = newHead;
        while (curr != null) {
            System.out.print(curr.currVal + ",");
            curr = curr.next;
        }
    }

    /**
     * 以K个节点为一组,进行反转
     * @param head
     * @param k
     * @return
     */
    public static ListNode reverseK(ListNode head, int k){
        //如果链表为 null 或者K < 1,无需反转
        if(head == null || k <= 1) {
            return head;
        }
        ListNode curr = head;
        //判断链表长度是否 < K,同时找到反转的链表尾标
        for(int i = 1; i < k && curr!=null; i++) {
            curr = curr.next;
        }
        //链表长度不足K,直接返回
        if(curr == null) {
            return head;
        }
        //此时,cur就是下表为K的节点,我们需要保存第(K+1),然后将K+1 - end 当成一个新的链表,进行递归
        ListNode nextList = curr.next;
        curr.next = null;
        //反转当前K个节点的链表
        ListNode newHead = reverse(head);
        // 递归处理后面链表
        ListNode newNext = reverseK(nextList,k);
        // 重新连接之前断开的链表
        head.next = newNext;
        // 返回反转后的新头节点
        return newHead;
    }

    /**
     * 反转链表
     */
    public static ListNode reverse(ListNode head) {
        //前一个节点的指针
        ListNode pre = null;
        //当前节点的指针
        ListNode curr = head;
        //下一个节点的指针
        ListNode next = null;
        //e.g. 1->2->3 ==> null<-1<-2<-3
        while(curr != null) {
            next = curr.next;
            curr.next = pre;
            pre = curr;
            curr = next;
        }
        return pre;
    }
}

执行结果

image.png

时间复杂度

因为要进行K次循环,所以时间复杂度为 O(nK)O(n∗K),最好的情况就是循环1次 O(1)O(1),最差则是循环n次 O(n2)O(n^2)

空间复杂度

这里没有额外占用其他控件,为O(1)O(1)

好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊