[Data structure] LeetCode question of linked list: 141. Circular linked list I, 4. Circular linked list II, 234. Palindrome linked list

141. Circular linked watch¹

Given a linked list, determine whether there is a ring in the linked list.

To show the list given ring, we use an integer posto indicate a position connected to the end of the list of the list (starting with index 0). If posis -1, there is no loop on this list

Example 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

img

Example 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

img

Example 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

img

Solution 1: Enumeration

  • Idea: Use a table to store all nodes, if the node is already in the table, there is a ring
    • The table here is best to use HashSet, because the contains method and add method of set are based on the hash table, and the complexity is O(1)–> 5ms
    • If ArrayList is used, the complexity of the contains method is O(n)–> 372ms
  • the complexity
    • Time : O (n)
    • Space: O(n), each node in the linked list must be placed in the container
public boolean hasCycle(ListNode head) {
    
    
        if (head == null || head.next == null) return false;

        ListNode node = head;
    	// 这里太合适用set了
        Set<ListNode> set = new HashSet<>();
        while(node.next != null) {
    
    
            if (set.contains(node)) 
                return true;
                set.add(node);
                node = node.next;
        }
        return false;
}

Solution 2: Double pointer (fast or slow)

  • Idea: If there is a loop, the pointer that goes fast (two steps at a time) must catch up with the slow pointer (one step at a time)
  • the complexity
    • Time : O (n)
    • Space:O(1)
public boolean hasCycle(ListNode head) {
    
    
        if (head == null || head.next == null) return false;

        ListNode qn = head,sn = head; // quickNode,slowNode
    	// 关键是这个判断条件
    	// qn != null 保证了 qn.next 不会出现空指针异常;
    	// qn.next != null 保证了 qn.next.next 不会出现空指针异常;
        while (qn != null && qn.next != null) {
    
     
            sn = sn.next;
            qn = qn.next.next;
            if (sn == qn) {
    
    
                return true;
            }
        }
        return false;
}

4. Circular linked list II²

Given a linked list, return the first node where the linked list starts to enter the loop. If the linked list has no rings, return null.

To show the list given ring, we use an integer posto indicate a position connected to the end of the list of the list (starting with index 0). If posis -1, there is no loop on this list.

Note : It is not allowed to modify the given linked list.

Example 1:

输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。

img

Example 2:

输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。

img

Example 3:

输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。

img

Solution 1: Double pointer (fast or slow)

  • Idea: This is actually a rule. After the fast and slow pointers meet, the start point of the loop is where the fast pointer meets the slow again from the beginning.
  • the complexity
    • Time : O (n)
    • Space:O(1)
public ListNode detectCycle(ListNode head) {
    
    
        ListNode fast = head;
        ListNode slow = head;
        // 让快慢指针相遇
        while (true) {
    
    
            // 无环判断
            // 注意:这里不能放到循环条件,假设,那么退出循环那部分如何操作?
            if (fast == null || fast.next == null) {
    
    
                return null;
            }
            fast = fast.next.next;
            slow = slow.next;
            // 定位到两指针相遇处
            if (slow == fast) {
    
    
                break;
            }
        }
    	// 将快指针从头开始,慢指针还在相遇处
        fast = head;
    	// 两指针再次相遇位置就是环始点
        while (fast != slow) {
    
    
            fast = fast.next;
            slow = slow.next;
        }

        return fast;
}

234. Palindrome Linked List

Please determine whether a linked list is a palindrome linked list.

Example 1:

输入: 1->2
输出: false

Example 2:

输入: 1->2->2->1
输出: true

Solution one: stack

  • Idea: Traverse the linked list, push all nodes onto the stack, and traverse again for comparison.
    Note: val should be stored in the stack, not ListNode. Because the order of comparison is reversed, ListNode must be different.
  • the complexity
    • Time : O (n)
    • Space: O(n), used a Stack
public boolean isPalindrome(ListNode head) {
    
    
        // 注:栈里存的是具体value,是Stack<Integer>,不是Stack<ListNode>
        Stack<Integer> stack = new Stack<>();
        // 注:链表用for遍历更简洁
        for (ListNode p = head; p != null; p = p.next) 
            stack.push(p.val);
        for (ListNode p = head; p != null; p = p.next)
            if (p.val != stack.pop())
                return false;
        return true;
    }

2. Solution 2: Compare in half

  • Idea: First reverse the first half of the linked list, and then simultaneously traverse and compare from the middle (dual pointer). But it should be noted that if the length is an odd number, the pointer (cur) that follows must be moved one bit backward
  • the complexity
    • Time : O (n)
    • Space:O(1)
public boolean isPalindrome(ListNode head) {
    
    
        // 1.计算链表长度
        int len = 0;
        for (ListNode p = head; p != null; p = p.next) len++;
		
        // 2.将链表前一半倒序,反转链表的模板
        ListNode cur = head, pre = null;
        for (int i = 0; i < len / 2; i++) {
    
    
            ListNode tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
		
    	// 注:若长度是奇数,则要将cur后移一位再比较
        if (len % 2 == 1) cur = cur.next;
    	// 3.从中间开始同时遍历前一半与后一半,比较val
        for (; pre != null && cur != null; pre = pre.next, cur = cur.next) 
            if (pre.val != cur.val)
                return false;

        return true;
    }

Guess you like

Origin blog.csdn.net/weixin_43935927/article/details/108738754