算法002:将单链表的每K个节点之间逆序,例子:假设m=3. 链表 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 ->8 output: 3 -> 2 -> 1 ->6 -.....

270 阅读3分钟
题目:
将head单链表以m为组反转链表(不足m则不反转):
例子:假设m=3. 链表 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 ->8
output: 3 -> 2 -> 1 ->6 ->5 ->4 -> 7 ->8

思路:
可以使用栈的结构解决这个问题,如果栈中值为K则弹出栈

使用栈的结构,时间复杂度O(n),控件复杂度为O(K)

1.代码如下:

1.1Node.java

package com.yuhl.right.node;

/**
 * @author yuhl
 * @Date 2020/10/24 15:36
 * @Classname Node
 * @Description TODO
 */
public class Node {
    private int value;
    private Node next;

    public Node() {
    }

    public Node(int value, Node next) {
        this.value = value;
        this.next = next;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

1.1NoteTest.java

package com.yuhl.right.node;

import com.yuhl.Main;

import java.util.Stack;

/**
 * @author yuhl
 * @Date 2020/10/24 15:38
 * @Classname NoteTest
 * @Description
 *
 * 将head单链表以m为组反转链表(不足m则不反转):
 * 例子:假设m=3. 链表 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 ->8
 * output: 3 -> 2 -> 1 ->6 ->5 ->4 -> 7 ->8
 */
public class NoteTest {
    public static void main(String[] args) {
        //构建单链表
        Node node8 = new Node(8, null);
        Node node7 = new Node(7, node8);
        Node node6 = new Node(6, node7);
        Node node5 = new Node(5, node6);
        Node node4 = new Node(4, node5);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node node1 = new Node(1, node2);
        Node nodeRev = getRevNode(node1,3);//获取旋转之后的链表
        printLinck(nodeRev, 8);//打印旋转之后的链表
    }

    /**
     * 使用栈的结构,时间复杂度O(n),控件复杂度为O(K)
     * @param head 头结点
     * @param K 每K个为一组
     * @return 新的头结点
     *
     */
    private static Node getRevNode(Node head, int K) {
        if (K < 2) {//如果仅有一个结点就返回当前头结点
            return head;
        }

        //栈中存放K个节点
        Stack<Node> stack = new Stack<>();
        Node newHead = head;//新的头结点,返回值用
        int count = 1;//计数,每到K则重置为1
        Node cur = head;//当前节点
        Node pre = null;//前一个节点
        Node next = null;//后一个节点
        while (cur != null) {
            next = cur.getNext();
            stack.push(cur);
            if (stack.size() == K) {
                pre = pesign1(stack, pre, next);
                newHead = newHead == head ? cur : newHead;//如果第一次进来newHead == head 取cur节点,要不然取newHead说明已经赋值过了。
            }
            cur = next;
        }
        return newHead;
    }

    private static Node pesign1(Stack<Node> stack, Node left, Node right) {
        Node cur = stack .pop();
        if (left != null) {
            left.setNext(cur);
        }
        Node next = null;
        while (!stack.isEmpty()) {
            next = stack.pop();
            cur.setNext(next);
            cur = next;
        }
        cur.setNext(right);
        return cur;

    }

    private static void printLinck(Node nodeRev, int len) {
        Node noteTem = nodeRev;
        for (int i = 0; i < len; i++) {
            if (i == len - 1) {//最后的一个结点后面无须->
                System.out.print(noteTem.getValue());
            } else {
                System.out.print(noteTem.getValue() + "->");

            }
            noteTem = noteTem.getNext();
        }
    }
}

2.运行结果如下:

"C:\Program Files\Java\jdk1.8.0_201\bin\java.exe"
3->2->1->6->5->4->7->8

3.运行结果如下:

更容易理解的方式写代码:

3.1 Node.java

package com.yuhl.test001.revNode;

/**
 * @author yuhl
 * @Date 2020/10/31 11:20
 * @Classname Node
 * @Description 链表选装的Node类
 */
public class Node {
    public int value;
    public Node next;

    public Node() {
    }

    public Node(int value, Node next) {
        this.value = value;
        this.next = next;
    }
}

3.2 RevNodeTest.java

package com.yuhl.test001.revNode;

import com.yuhl.right.tree1.TreeNodeTest2;

import java.util.Stack;

/**
 * @author yuhl
 * @Date 2020/10/31 11:21
 * @Classname RevNodeTest
 * @Description 算法002:将单链表的每K个节点之间逆序,例子:假设m=3. 链表 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 ->8 output: 3 -> 2 -> 1 ->6 -.
 * 旋转的方法,入栈会简单很多。
 */
public class RevNodeTest {
    public static void main(String[] args) {
        //构建单链表
        Node node8 = new Node(8, null);
        Node node7 = new Node(7, node8);
        Node node6 = new Node(6, node7);
        Node node5 = new Node(5, node6);
        Node node4 = new Node(4, node5);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node head = new Node(1, node2);
        Node newHead = revNode(head, 4);
        printnewHead(newHead);
    }

    //打印链表
    private static void printnewHead(Node newHead) {
        Node tmpNode = newHead;
        while (true) {
            if (tmpNode != null) {
                System.out.print(tmpNode.value+ " ");
                if (tmpNode.next != null) {
                    tmpNode = tmpNode.next;
                } else {
                    break;
                }
            }
        }

    }

    public static Node revNode(Node head,int len){
        if (head.next == null || len <= 1) {//如果只有一个结点,则直接返回
            return head;
        }
        Node newHead = null;//返回的新的链表的头部
        Node curNode = head;//临时节点,入栈使用
        Node tmpNode = null;//临时节点: 出栈使用
        Node preNode = null;//N 个节点的最后一个,用于N+1个节点往前连接
        Node noRevNode = null;//记录每次入栈的第一个,有可能是不逊转的。
        Node preNodeSer = null;//弹出stack时的前置节点
        //入栈
        Stack<Node> stack = new Stack();
        int flag = 1;//为1:可以旋转,0为不可以旋转,不足len
        while(flag == 1){
            //入栈
            for (int i = 1; i <= len; i++) {
                if(i == 1){
                    noRevNode = curNode;
                }
                stack.push(curNode);
                if (curNode.next != null) {
                    curNode = curNode.next;
                } else {
                    //把n的最后一个结点接在现在的节点上。
                    flag = 0; //可以旋转,
                    break;//不足len,不旋转
                }
            }

            //出栈
            if (stack.size() == len) { //旋转
                for (int i = 1; i <= len; i++) {
                    Node popNode = stack.pop();
                    tmpNode = popNode;

                    if (newHead == null) {//第一次弹出,就是新的首节点,要不然首节点已经被占说明是>1次的弹出
                        newHead = popNode;
                        preNodeSer = popNode;
                    } else {
                        preNodeSer.next = tmpNode;
                        preNodeSer = tmpNode;
                        if(i == len){//记录下次节点需要连上的上次的节点
                            preNode = popNode;// preNode = tmpNode;
                            if (0 == flag) {
                                preNode.next = null;//要不然会循环打印
                            }
                        }
                    }
                }
            } else {//不旋转
                if (newHead == null) {//如果len>size时使用
                    return head;
                }
                preNode.next = noRevNode;
            }

            if (tmpNode.next == null) {
                flag = 0;
            }
        }
        return newHead;
    }
}

3.3 运行结果

4 3 2 1 8 7 6 5