Water2Wine

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
反转链表类的题型整体来说有两种解法,一种就是利用java特有的泛型,用栈的数据结构进行反转;另一种则是用多指针原地逐个反转。两种解法各有优缺,第一种胜在逻辑简单,但是空间复杂度较高;第二种逻辑上较为复杂,但是空间复杂度低

一、反转整个链表

泛型+栈的解法:

private static Node reverseNodeByStack(Node root) {
        Stack<Node> stack = new Stack<>();
        while (root != null) {
            stack.add(root);
            root = root.next;
        }
        Node root1 = stack.pop();
        Node temp = root1;
        while (!stack.isEmpty()) {
            temp.next = stack.pop();
            temp = temp.next;
        }
        temp.next = null;
        return root1;
    }

三指针原地反转:

private static Node reverseNodeByIndex(Node root) {
        // 就地反转,需要三个指针
        Node pre = null;
        Node middle = root;
        Node next = middle.next;
        while (next != null) {
            middle.next = pre;
            pre = middle;
            middle = next;
            next = next.next;
        }
        middle.next = pre;
        return middle;
    }

二、反转部分链表

泛型+栈的解法:

private static Node reverseNodeByStack(Node root, int from, int to) {
        int index = 0;
        Node start = root;
        for (int i = 1;i < from - 1;i++) {
            start = start.next;
        }
        Stack<Node> stack = new Stack<>();
        Node temp1 = start.next;
        for (int i = 0;i <= to - from;i++) {
            stack.add(temp1);
            temp1 = temp1.next;
        }
        Node end = temp1;
        while (!stack.isEmpty()) {
            start.next = stack.pop();
            start = start.next;
        }
        start.next = end;
        return root;
    }

三、判断链表是否回文中的反转链表应用

判断链表是否回文本质上和反转链表的原理相同

可以使用泛型+栈的解法,将一半的链表入栈,然后与后半部分对比

也可以先使用原地反转将后半部分反转,然后前后指针同时遍历判断是否回文,不过要记得无论是否回文,判断完后要先将链表反转回来,再返回值

泛型+栈的解法:

private static boolean simplePalindrome(Node head) {
        // 简单的方式就是用栈即可
        // 先判断一下链表长度
        int length = 0;
        Node temp1 = head;
        while (temp1 != null) {
            temp1 = temp1.next;
            length++;
        }
        Stack<Node> stack = new Stack<>();
        Node temp2 = head;
        for (int i = 0;i < length / 2;i++) {
            stack.add(temp2);
            temp2 = temp2.next;
        }
        if (length % 2 == 1) {
            temp2 = temp2.next;
        }
        for (int i = 0;i < length / 2;i++) {
            if (temp2.value != stack.peek().value) {
                return false;
            } else {
                stack.pop();
                temp2 = temp2.next;
            }
        }
        return true;
    }

反转后半链表的解法:

private static boolean fastPalindrome(Node head) {
        // 反转后半链表要记得,无论是否回文,都要先将链表反转回来再返回
        if (head == null || head.next == null) {
            return true;
        }
        // 空间复杂度O(1)的做法是将后半段链表反转,并前后同时遍历
        // 第一步应该是判断链表长度,同时获得反转链表的起点,可以使用双指针法来做
        Node slow = head;
        Node fast = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        // 从slow开始反转
        Node pre = null;
        Node middle = slow;
        Node next = middle.next;
        while (middle.next != null) {
            middle.next = pre;
            pre = middle;
            middle = next;
            next = next.next;
        }
        middle.next = pre;
        // 现在得到了Middle和head
        Node start = head;
        Node end = middle;
        boolean ans = true;
        while (start != null) {
            if (start.value != end.value) {
                ans = false;
                break;
            } else {
                start = start.next;
                end = end.next;
            }
        }
        // 将反转的后半部分再反转回来
        pre = null;
        next = middle.next;
        while (next != null) {
            middle.next = pre;
            pre = middle;
            middle = next;
            next = next.next;
        }
        middle.next = pre;
        return ans;
    }
posted on 2020-06-07 13:14  Water2Wine  阅读(166)  评论(0编辑  收藏  举报