算法入门篇五 链表

牛客网 算法入门篇

判断一个链表是否为回文结构

  • 给定一个单链表的头节点head,请判断这个链表是否为回文结构
  • 1->2->1,返回为True;1->2->3为False

思路:

  • 1,遍历链表,将所有元素压入栈中,然后再次从头遍历,和栈中取出的元素比较。如果所有元素都是一致的化,说明是属于回文结构的。
  • 2,不是将所有的元素都入栈,只是将一般的元素压入栈中,引出新的问题,如何确认链表的中点?设计快指针和慢指针,快指针每次移动2步,慢指针每次移动1步,当快指针移动到末尾,慢指针所指向的位置就是链表的中点位置。但是,链表长度需要分奇数和偶数。(节约空间
  • 3,不需要使用栈,仅仅使用有限几个变量。和方法2一致,使用快慢指针找到链表的中点,将链表中点之后的元素逆序,然后逐一比较,但是需要注意的是,最后需要将链表变回原先的样子。

代码:

package class04;
 
import java.util.Stack;
 
public class Code04_IsPalindromeList {
 
    public static class Node {
        public int value;
        public Node next;
 
        public Node(int data) {
            this.value = data;
        }
    }
 
    // need n extra space
    public static boolean isPalindrome1(Node head) {
        Stack<Node> stack = new Stack<Node>();
        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 right = head.next;
        Node cur = head;
        while (cur.next != null && cur.next.next != null) {
            right = right.next;
            cur = cur.next.next;
        }
        Stack<Node> stack = new Stack<Node>();
        while (right != null) {
            stack.push(right);
            right = right.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) { // find mid node
            n1 = n1.next; // n1 -> mid
            n2 = n2.next.next; // n2 -> end
        }
        n2 = n1.next; // n2 -> right part first node
        n1.next = null; // mid.next -> null
        Node n3 = null;
        while (n2 != null) { // right part convert
            n3 = n2.next; // n3 -> save next node
            n2.next = n1; // next of right node convert
            n1 = n2; // n1 move
            n2 = n3; // n2 move
        }
        n3 = n1; // n3 -> save last node
        n2 = head;// n2 -> left first node
        boolean res = true;
        while (n1 != null && n2 != null) { // check palindrome
            if (n1.value != n2.value) {
                res = false;
                break;
            }
            n1 = n1.next; // left to mid
            n2 = n2.next; // right to mid
        }
        n1 = n3.next;
        n3.next = null;
        while (n1 != null) { // recover list
            n2 = n1.next;
            n1.next = n3;
            n3 = n1;
            n1 = n2;
        }
        return res;
    }
 
    public static void printLinkedList(Node node) {
        System.out.print("Linked List: ");
        while (node != null) {
            System.out.print(node.value + " ");
            node = node.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("=========================");
 
    }
 
}

将单链表按照给定的数值,划分成左边小、中间相等、右边大的形式

思路

  • 1,申请一个链表长度大小一致的数组,然后遍历链表的过程中,将每一个点放到数组容器中,在数组里面进行荷兰国旗问题,再把数组容器中的元素都串联起来,形成一个链表返回

  • 2,保证稳定性:根据题目要求设置三个区,小于区、等于区和大于区,每个区间包含两个变量,开始节点和结尾节点,一共设置6个变量,6个变量都指向null;当遇到第一个元素3的时候,它是小于指定元素5的,将小于区域的开始和结束指针都指向3;第二个元素是5,属于等于区,让等于区的start和end都指向第二个元素5;第3个元素也是5,让等于区的end只想第三个元素。以此类推,得到上面的结果。最后将小于区域的end指针链接等于区域的start指针,等于区域的end指针链接大于区域的start指针。需要注意的是,有可能上面6个变量有不存在的情形,需要仔细判别。

两个单链表相交的一系列问题

  • 给定两个可能有环也可能无环的单链表,头节点head1和head2,实现一个函数,如果两个链表相交,返回相交的第一个节点,如果不相交,返回null
  • 两个链表的长度之和为N,时间复杂度为O(N),额外空间复杂度为O(1)
  • 相交:共用内存地址  
  • 有环/无环:写一个函数,输入的类型是链表的头节点,判断是否有环,以及返回第一个有环的节点。使用集合来做,遍历链表,每遍历一个元素,将其放入到集合中,判定是否存在此元素,如果将一个元素放入集合中,发现他已经存在,则是有环的,并且他就是第一个入环节点。

  • 使用快慢指针来做,快指针每次移动俩个位置,慢指针每次移动一个位置,当快慢指针第一次相交之后,快指针回到链表的起始点,慢指针呆在原地不动。然后快指针和慢指针都每次移动一个位置,当他们再次相遇之后,相遇的元素就是入环的第一个元素,且能证明这个链表是有环的结构。上图所示的是环外4个点,环内4个点,可以按照这个流程走一遍。
  • 两个无环链表相交问题,哪个链表长,先走比短链表多余的部分,然后一起走,只要有一点的内存地址相稳合,则代表两者相交。
  • 如果一个是有环的,一个是无环的,那么他俩一定不相交

  • 如果两者都是环状结构,那么可以划分为上面三种形式。1,两者都是环,都不相交;2,两者共用环,却已经在环外相交,入环点一样;3,共用环,但是接入环的点不一样。
  • 第一种情形,如上图的左边的图形“6”,loop1为相交点,让loop1顺着next指针走一圈,如果走了一圈没有遇到loop2,则二者不相交。
  • 第二种类型,只需要判断二者的入环节点是否一致,就可以判定是否相交。如果需要判断相交的第一个节点,入环点作为终止节点,转化为先前的长短链,找相交点。
  • 第一种情形,如上图的右边的图形所示,loop1为左边的相交点,loop2为右边的相交点,让loop1顺着next指针走一圈,如果走了一圈遇到loop2,则二者相交。loop1 和loop2都是相交节点,只不过loop1距离链表1更近,loop2距离链表2更近。
package class04;
 
public class Code07_FindFirstIntersectNode {
 
    public static class Node {
        public int value;
        public Node next;
 
        public Node(int data) {
            this.value = data;
        }
    }
 
    public static Node getIntersectNode(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 n1 = head.next; // n1 -> slow
        Node n2 = head.next.next; // n2 -> fast
        while (n1 != n2) {
            if (n2.next == null || n2.next.next == null) {
                return null;
            }
            n2 = n2.next.next;
            n1 = n1.next;
        }
        n2 = head; // n2 -> walk again from head
        while (n1 != n2) {
            n1 = n1.next;
            n2 = n2.next;
        }
        return n1;
    }
 
    // 如果两个链表都无环,返回第一个相交节点,如果不想交,返回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  :  链表1长度减去链表2长度的值
        cur1 = n > 0 ? head1 : head2; // 谁长,谁的头变成cur1
        cur2 = cur1 == head1 ? head2 : head1; // 谁短,谁的头变成cur2
        n = Math.abs(n);
        while (n != 0) {
            n--;
            cur1 = cur1.next;
        }
        while (cur1 != cur2) {
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return cur1;
    }
 
    // 两个有环链表,返回第一个相交节点,如果不想交返回null
    public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
        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(getIntersectNode(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(getIntersectNode(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(getIntersectNode(head1, head2).value);
 
    }
 
}

 

猜你喜欢

转载自blog.csdn.net/CHYabc123456hh/article/details/106680065