算法与数据结构基础学习六(链表问题总结)

本文探讨了链表的多种操作,包括使用快慢指针寻找链表中点及前后节点,判断链表是否为回文,以及链表排序和查找链表相交节点的方法。详细介绍了不同算法的时间复杂度和实现细节,涵盖了基础的链表操作和高级的链表问题解决策略。
摘要由CSDN通过智能技术生成

快慢指针

在这里插入图片描述


public class LinkedListMid {
    public static class Node{
        public int value;
        public Node next;
        public Node(int value){
            this.value = value;
        }
    }

    //输入链表头节点,奇数长度返回中点,偶数长度返回上中点
    //快慢指针实现
    public static Node midOrUpMidNode(Node head){
        if (head == null || head.next == null || head.next.next == null){
            return head;
        }
        Node slow = head.next;
        Node fast = head.next.next;
        while (fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
    //输入链表头节点,奇数长度返回中点,偶数长度返回下中点
    public static Node midOrDownMidNode(Node head){
        if (head == null || head.next == null || head.next.next == null){
            return head;
        }
        Node slow = head.next;
        Node fast = head.next;
        while (fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
    //输入链表头节点,奇数长度返回中点前一个,偶数长度返回上中点前一个
    public static Node midOrUpMidPreNode(Node head){
        if (head == null || head.next == null || head.next.next == null){
            return null;
        }
        Node slow = head;
        Node fast = head.next.next;
        while (fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
    //输入链表头节点,奇数长度返回中点前一个,偶数长度返回下中点前一个
    public static Node midOrDownMidPreNode(Node head){
        if (head == null || head.next == null){
            return null;
        }
        Node slow = head;
        Node fast = head.next;
        while (fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;

    }
    public static Node right1(Node head){
        if (head == null){
            return null;
        }
        Node cur = head;
        ArrayList<Node> arr = new ArrayList<>();
        while (cur!=null){
            arr.add(cur);
            cur = cur.next;
        }
        return arr.get((arr.size()-1)/2);
    }
    public static Node right2(Node head) {
        if (head == null) {
            return null;
        }
        Node cur = head;
        ArrayList<Node> arr = new ArrayList<>();
        while (cur != null) {
            arr.add(cur);
            cur = cur.next;
        }
        return arr.get(arr.size() / 2);
    }

    public static Node right3(Node head) {
        if (head == null || head.next == null || head.next.next == null) {
            return null;
        }
        Node cur = head;
        ArrayList<Node> arr = new ArrayList<>();
        while (cur != null) {
            arr.add(cur);
            cur = cur.next;
        }
        return arr.get((arr.size() - 3) / 2);
    }

    public static Node right4(Node head) {
        if (head == null || head.next == null) {
            return null;
        }
        Node cur = head;
        ArrayList<Node> arr = new ArrayList<>();
        while (cur != null) {
            arr.add(cur);
            cur = cur.next;
        }
        return arr.get((arr.size() - 2) / 2);
    }
    public static void main(String[] args) {
        Node test = null;
        test = new Node(0);
        test.next = new Node(1);
        test.next.next = new Node(2);
        test.next.next.next = new Node(3);
        test.next.next.next.next = new Node(4);
        test.next.next.next.next.next = new Node(5);
        test.next.next.next.next.next.next = new Node(6);
        test.next.next.next.next.next.next.next = new Node(7);
        test.next.next.next.next.next.next.next.next = new Node(8);

        Node ans1 = null;
        Node ans2 = null;

        ans1 = midOrUpMidNode(test);
        ans2 = right1(test);
        System.out.println(ans1 != null ? ans1.value : "无");
        System.out.println(ans2 != null ? ans2.value : "无");

        ans1 = midOrDownMidNode(test);
        ans2 = right2(test);
        System.out.println(ans1 != null ? ans1.value : "无");
        System.out.println(ans2 != null ? ans2.value : "无");

        ans1 = midOrUpMidPreNode(test);
        ans2 = right3(test);
        System.out.println(ans1 != null ? ans1.value : "无");
        System.out.println(ans2 != null ? ans2.value : "无");

        ans1 = midOrDownMidPreNode(test);
        ans2 = right4(test);
        System.out.println(ans1 != null ? ans1.value : "无");
        System.out.println(ans2 != null ? ans2.value : "无");

    }

}

回文问题

在这里插入图片描述

import java.util.Stack;

public class IsPalindromeList {
    public static class Node{
        public int value;
        public Node next;
        public Node(int value){
            this.value = value;
        }
    }
    //判断链表是否属于回文
    //need n extra space
    public static boolean isPalindrome1(Node head){
        if (head == null){
            return true;
        }
        Stack<Node> stack = new Stack<>();
        Node cur = head;
        while (cur != null){
            stack.push(cur);
            cur = cur.next;
        }
        while (head != null){
            if (head.value != stack.pop().value){
                return false;
            }
            head = head.next;
        }
        return true;
    }
    //need n/2 extra space
    //判断是否为回文
    public static boolean isPalindrome2(Node head){
        if (head == null || head.next == null){
            return true;
        }
        Node rihgt = head.next;
        Node cur = head;
        while (cur.next != null && cur.next.next != null){
            rihgt = rihgt.next;
            cur = cur.next.next;
        }
        Stack<Node> stack = new Stack<>();
        while (rihgt != null){
            stack.push(rihgt);
            rihgt = rihgt.next;
        }
        while (!stack.isEmpty()){
            if (head.value != stack.pop().value){
                return false;
            }
            head = head.next;
        }
        return true;
    }
    //need O(1) extra space
    //回文
    public static boolean isPalindrome3(Node head){
        if (head == null || head.next == null){
            return true;
        }
        //找到链表中点和终点
        Node n1 = head;
        Node n2 = head;
        while (n2.next != null && n2.next.next != null){
            n1 = n1.next;
            n2 = n2.next.next;
        }
        //反转后半部分链表
        n2 = n1.next; //n2-->right part first node
        n1.next = null; // mid.next = null
        Node n3 = null;
        while (n2 != null){
            n3 = n2.next; // n3-->save next node
            n2.next = n1; // 反转
            n1 = n2;
            n2 = n3;
        }
        n3 = n1; //保存右边反转后头节点
        n2 = head; //左边头节点
        boolean res = true;
        while (n1 != null && n2 != null){
            if (n1.value != n2.value){
                res = false;
                break;
            }
            n1 = n1.next;
            n2 = n2.next;
        }
        //将反转的链表再反转回来
        n1 = null;
        n2 = null;
        while (n3 != null){
            n1 = n3.next;
            n3.next = n2;
            n2 = n3;
            n3 = n1;
        }
        return res;
    }
    //for test
    public static void printLinkedList(Node head){
        System.out.print("Linked list: ");
        while (head != null){
            System.out.print(head.value+" ");
            head = head.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Node head = null;
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(3);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(3);
        head.next.next.next = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(2);
        head.next.next.next = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(3);
        head.next.next.next = new Node(2);
        head.next.next.next.next = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

    }
}

链表排序

在这里插入图片描述

import java.util.ArrayList;
public class SmallEqualBigger {
    public static class Node{
        public int value;
        public Node next;
        public Node(int value){
            this.value = value;
        }
    }

    public static Node listPartition1(Node head,int pivot){
        if (head == null || head.next == null){
            return head;
        }
        Node cur = head;
        int i =0;
        while (cur != null){
            i++;
            cur = cur.next;
        }
        Node[] nodeArr = new Node[i];
        i=0;
        cur = head;
        while (cur != null){
            nodeArr[i] = cur;
            cur = cur.next;
            i++;
        }
        arrPartition(nodeArr,pivot);
        for (i=1;i != nodeArr.length;i++){
            nodeArr[i-1].next = nodeArr[i];
        }
        nodeArr[i-1].next = null;
        return nodeArr[0];

    }

    private static void arrPartition(Node[] nodeArr, int pivot) {
        int small = -1;
        int big = nodeArr.length;
        int index = 0;
        while (index!=big){
            if (nodeArr[index] !=null && nodeArr[index].value < pivot){
                swap(nodeArr,index++,++small);
            }else if (nodeArr[index]!= null &&nodeArr[index].value == pivot){
                index++;
            }else {
                swap(nodeArr,index,--big);
            }
        }
    }

    private static void swap(Node[] nodeArr, int i, int i1) {
        Node tmp = nodeArr[i];
        nodeArr[i] = nodeArr[i1];
        nodeArr[i1] = tmp;
    }

    //分成小、中、大三部分,再把各个部分之间串起来
    public static Node listPartition2(Node head,int pivot){
        Node sH = null; //small head
        Node sT = null; //small tail
        Node eH = null; //equal head
        Node eT = null; //equal tail
        Node mH = null; //big head
        Node mT = null; //big tail
        Node next = null; //save next node
        //every node distributed to three lists
        while (head != null){
            next = head.next;
            head.next = null;
            if (head.value < pivot){
                if (sH == null){
                    sH = head;
                    sT = head;
                }else {
                    sT.next = head;
                    sT = head;
                }
            }else if (head.value == pivot){
                if (eH == null){
                    eH = head;
                    eT = head;
                }else {
                    eT.next = head;
                    eT = head;
                }
            }else {
                if (mH == null){
                    mH = head;
                    mT = head;
                }else {
                    mT.next = head;
                    mT = head;
                }
            }
            head = next;
        }
        //小于区的尾巴连等于区的头。等于区的尾巴连大于去的头
        if (sT != null){
            sT.next = eH;
            eT = eT == null ? sT : eT; //下一步,谁去连大于区的头谁就取eT
        }
        // 下一步,一定是需要用eT 去接 大于区域的头
        // 有等于区域,eT -> 等于区域的尾结点
        // 无等于区域,eT -> 小于区域的尾结点
        // eT 尽量不为空的尾巴节点
        if (eT != null){
            eT.next = mH;
        }
        return sH != null ? sH : (eH != null ? eH : mH);
    }
    public static void printLinkedList(Node head){
        System.out.print("Linked list: ");
        while (head != null){
            System.out.print(head.value+" ");
            head = head.next;
        }
        System.out.println();
    }
    public static void main(String[] args) {
        Node head1 = new Node(7);
        head1.next = new Node(9);
        head1.next.next = new Node(1);
        head1.next.next.next = new Node(8);
        head1.next.next.next.next = new Node(5);
        head1.next.next.next.next.next = new Node(2);
        head1.next.next.next.next.next.next = new Node(5);
        printLinkedList(head1);
        head1 = listPartition1(head1, 4);
        //head1 = listPartition2(head1, 5);
        printLinkedList(head1);

    }
}

一种特殊链表

在这里插入图片描述


import java.util.HashMap;

public class CopyListWithRandom {
    public static class Node{
        public int val;
        public Node next;
        public Node random;
        public Node(int value){
            this.val = value;
            this.next = null;
            this.random = null;
        }
    }
    //给定一个由Node节点类型组成的无环单链表的头节点 head,请实现一个函数完成这个链表的复制,并返回复制的新链表的头节点。
    public static Node copyRandomList1(Node head){
        //key 老节点
        //value 新节点
        HashMap<Node, Node> map = new HashMap<>();
        Node cur = head;
        while (cur != null){
            map.put(cur,new Node(cur.val));
            cur = cur.next;
        }
        cur = head;
        while (cur != null){
            // cur 老
            //map.get(cur) 新
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        return map.get(head);
    }

    public static Node copyRandomList2(Node head){
        if (head == null){
            return null;
        }
        Node cur = head;
        Node next = null;
        // 1 -> 2 -> 3 -> null
        // 1 -> 1' -> 2 -> 2' -> 3 -> 3'
        while (cur != null){
            next = cur.next;
            cur.next = new Node(cur.val);
            cur.next.next = next;
            cur = next;
        }
        cur = head;
        Node copy = null;
        while (cur != null){
            next = cur.next.next;
            copy = cur.next;
            copy.random = cur.random != null ? cur.random.next : null;
            cur = next;
        }
        //在next方向上把新 老链分离
        cur = head;
        Node res = head.next;
        while (cur != null){
            next = cur.next.next;
            copy = cur.next;
            cur.next = next;
            copy.next = next != null? next.next : null;
            cur = next;
        }
        return res;
    }
}

链表环

在这里插入图片描述


public class FindFirstIntersectNode {
    //给定两个可能有环也可能无环的单链表,头节点head1和head2。请实现一个函数,如果两个链表相交,请返回相交的 第一个节点。如果不相交,返回null
    //如果两个链表长度之和为N,时间复杂度请达到O(N),额外空间复杂度 请达到O(1)
    public static class Node{
        public int value;
        public Node next;
        public Node(int value){
            this.value = value;
        }
    }
    public static Node getInsertNode(Node head1,Node head2){
        if (head1 == null || head2 == null){
            return null;
        }
        Node loop1 = getLoopNode(head1);
        Node loop2 = getLoopNode(head2);
        if (loop1 == null && loop2 == null){
            return noLoop(head1,head2);
        }
        if (loop1 != null && loop2 != null){
            return bothLoop(head1,loop1,head2,loop2);
        }
        return null;
    }
    //找到链表的第一个入环节点,如果无环,返回null
    public static Node getLoopNode(Node head){
        if (head == null || head.next == null || head.next.next == null){
            return  null;
        }
        Node slow = head.next;
        Node fast = head.next.next;
        //追击问题,跑的快的在环里总会跟跑的慢的相遇,
        while (slow != fast){
            if (fast.next == null || fast.next.next == null){
                return null;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        fast = head;
        //相遇后,跑的快的回到起点保持和慢一样的速度,相遇时就是环的节点
        while (fast != slow){
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
    //如果两个链表都没环,返回第一个相交点, 如果不相交返回null
    public static Node noLoop(Node head1,Node head2){
        if (head1 == null || head2 == null){
            return null;
        }
        Node cur1 = head1;
        Node cur2 = head2;
        int n=0;
        while (cur1.next != null){
            n++;
            cur1 = cur1.next;
        }
        while (cur2.next != null){
            n--;
            cur2 = cur2.next;
        }
        if (cur1 != cur2){
            return null;
        }
        // n -> head1 - head2 的长度的值
        cur1 = n > 0 ? head1 : head2; //谁长,谁的头变成cur1
        cur2 = cur1 == head1 ? head2 :head1; //短的链表头变成cur2
        n = Math.abs(n);
        while (n !=0){
            n--;
            cur1 = cur1 != null ? cur1.next : null;
        }
        //此时cur1、cur2两个链表长度一样
        while (cur1 != cur2){
            cur1 = cur1 != null ? cur1.next : null;
            cur2= cur2 != null ? cur2.next : null;
        }
        return cur1;
    }
    //两个有环列表,相交返回第一个相交点,不相交返回null
    public static Node bothLoop(Node head1,Node loop1,Node head2,Node loop2){
        if (head1 == null || head2 == null){
            return null;
        }
        Node cur1 = null;
        Node cur2 = null;
        //如果入环节点一样,相交必在入环前
        if (loop1 == loop2){
            cur1 = head1;
            cur2 = head2;
            int n = 0;
            while (cur1 != loop1){
                n++;
                cur1 = cur1.next;
            }
            while (cur2 != loop2){
                n--;
                cur2 = cur2.next;
            }
            cur1 = n>0 ? head1:head2;
            cur2 = cur1 == head1 ? head2 : head1;
            n = Math.abs(n);
            while (n!=0){
                n--;
                cur1 = cur1.next;
            }
            while (cur1 != cur2){
                cur1 = cur1.next;
                cur2 = cur2.next;
            }
            return cur1;
        }else {
            cur1 = loop1.next;
            while (cur1 != loop1){
                if (cur1 == loop2){
                    return loop1;
                }
                cur1 = cur1.next;
            }
            return null;
        }
    }
    public static void main(String[] args) {
        // 1->2->3->4->5->6->7->null
        Node head1 = new Node(1);
        head1.next = new Node(2);
        head1.next.next = new Node(3);
        head1.next.next.next = new Node(4);
        head1.next.next.next.next = new Node(5);
        head1.next.next.next.next.next = new Node(6);
        head1.next.next.next.next.next.next = new Node(7);

        // 0->9->8->6->7->null
        Node head2 = new Node(0);
        head2.next = new Node(9);
        head2.next.next = new Node(8);
        head2.next.next.next = head1.next.next.next.next.next; // 8->6
        System.out.println(getInsertNode(head1, head2).value);

        // 1->2->3->4->5->6->7->4...
        head1 = new Node(1);
        head1.next = new Node(2);
        head1.next.next = new Node(3);
        head1.next.next.next = new Node(4);
        head1.next.next.next.next = new Node(5);
        head1.next.next.next.next.next = new Node(6);
        head1.next.next.next.next.next.next = new Node(7);
        head1.next.next.next.next.next.next = head1.next.next.next; // 7->4

        // 0->9->8->2...
        head2 = new Node(0);
        head2.next = new Node(9);
        head2.next.next = new Node(8);
        head2.next.next.next = head1.next; // 8->2
        System.out.println(getInsertNode(head1, head2).value);

        // 0->9->8->6->4->5->6..
        head2 = new Node(0);
        head2.next = new Node(9);
        head2.next.next = new Node(8);
        head2.next.next.next = head1.next.next.next.next.next; // 8->6
        System.out.println(getInsertNode(head1, head2).value);

    }

}

from —左程云算法基础课

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值