Three steps of single linked list problem solving

1, Concept

The linked list is composed of a group of scattered nodes connected by pointers. Each node contains the current node content and subsequent pointers. Compared with array, it is not restricted by storage space and can be inserted and deleted more quickly. There are mainly the following types:

1. Single linked list

The pointer points to the next node and the endpoint points to null

2. Double linked list

Pointer to the previous node and the next node

3. Circular linked list

The last node points to the first node

When solving problems related to linked lists, it will be clearer to perform three steps first and then tap the code

  • Determine the type of linked list for problem solving
  • Draw pictures and clarify ideas
  • Determining boundary conditions

Unlike arrays, JS has not yet provided a direct linked list API. Linked lists can be simulated through objects. The structure is

const head = {
  data: 1,
  next: {
    data: 2,
    next: null,
  },
};

2, leetcode most common related questions

1,Merge two ordered linked lists

Merge the two ascending linked lists into a new ascending linked list and return. The new linked list is composed by splicing all nodes of the given two linked lists

Example:
  input: l1 = [1,2,4], l2 = [1,3,4]
  output: [1,1,2,3,4,4]

Steps:

  • The linked list type for problem solving is single linked list
  • Idea:
    • L1 and L2 are sequentially increasing, so l1 Val and l2 The smaller value of Val is the minimum value of the merged linked list
    • Recurse the comparison of size nodes in turn until L1 and L2 are null
  • Boundary condition: recursion can be stopped when any linked list is null, and the next point to another linked list
var mergeTwoLists = function(l1, l2) { 
    if (l1 === null) {
        return l2
    } else if (l2 === null) {
        return l1
    } else if (l1.val < l2.val) {
        l1.next = mergeTwoLists(l1.next, l2)
        return l1
    } else {
        l2.next = mergeTwoLists(l2.next, l1)
        return l2
    }
};

2,Circular linked list

Given a linked list, judge whether there are links in the linked list. If there is a node in the linked list that can be reached again by continuously tracking the next pointer, there is a ring in the linked list. If there are rings in the linked list, return true; otherwise, return false. O(1) memory is required to solve this problem

pos indicates that the end of the linked list is connected to the position in the linked list. If pos is -1, there is no ring in the linked list

Example:
  Input: head = [3,2,0,-4], pos = 1 
  Output: true  // There is a ring in the linked list, and its tail is connected to the second node

Steps:

  • The linked list type for problem solving is single linked list
  • Idea:
    • Tortoise and rabbit race algorithm: use the fast and slow double pointers, the fast pointer takes two steps, and the slow pointer takes one step
    • If there are links in the linked list, two pointers with different speeds must meet. And go down from the meeting point and the chain header node at the same time, and you will meet at the starting point of the ring
  • Boundary conditions:
    • Fast pointer to null stop, no loop
    • The fast and slow pointers point to the same node with a ring
var hasCycle = function(head) {
    if(!head || !head.next) return false;
    let slow = head.next;
    let fast = head.next.next;
    while(slow !== fast ) {
        if(!fast || !fast.next) return false;
        slow = slow.next;
        fast = fast.next.next;
    }
    return true
}

3,Reverse linked list

Here is the head node of the single linked list. Please use iteration or recursion to reverse the linked list and return the reversed linked list

Example:
  input: head = [1,2,3,4,5]
  output: [5,4,3,2,1]

Steps:

  • The linked list type for problem solving is single linked list
  • Iteration idea:
    • Point the subsequent pointer of each node of the single linked list to its predecessor node

  • Boundary conditions:
    • Stop when the linked list is null
    • The linked list has only one node
var reverseList = function(head) {
    if(!head || !head.next) return head;
    let prev = null;
    let cur = head;
    while(cur) {
        const curNext = cur.next;
        // Assign to prev pointer after inversion
        cur.next = prev;
        prev = cur;
        // Link to next node
        cur = curNext;
    }
    return prev
};

4,Intermediate node of linked list

Given a non empty single linked list whose head node is head, return the intermediate node of the linked list. If there are two intermediate nodes, return the second intermediate node (the number of nodes in the given linked list is between 1 and 100)

Example:
  input: [1,2,3,4,5]
  output:  3
  input: [1,2,3,4,5,6]
  output:  4

Steps:

  • The linked list type for problem solving is single linked list
  • Idea:
    • The displacement of the fast pointer p2 is twice that of the slow pointer p1, so when p2 reaches the end of the list, p1 has just walked half way and points to the midpoint of the list.
    • The same is true for the following questions

  • Boundary conditions:
    • When the fast pointer points to null, the slow pointer is just in the middle position
var middleNode = function(head) {
    if(!head || !head.next) return head;
    let slow = head;
    let fast = head;
    while(fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow
};

5,Delete the penultimate node of the linked list

Give you a linked list, delete the penultimate node of the linked list, and return the head node of the linked list

Example:
  Input: head = [1,2,3,4,5], n = 2
  Output:[1,2,3,5]

Steps:

  • The linked list type for problem solving is single linked list

  • Idea:

    • The fast pointer walks through n nodes at a time, and then the two pointers walk back together until the fast pointer points to null. At this time, the slow pointer is the penultimate node
    • Add sentry to process the nth node
  • Boundary conditions:

    • When the fast pointer points to null, the position of the slow pointer is the penultimate node
const removeNthFromEnd = function (head, n) {
  // sentry
  let preHead = new ListNode(0)
  preHead.next = head
  let slow = preHead;
  let fast = preHead;
  // Take n steps first
  while (n--) {
    fast = fast.next
  }
  // went together
  while (fast && fast.next) {
    fast = fast.next
    slow = slow.next
  }
  slow.next = slow.next.next
  return preHead.next;
};

6,Palindrome linked list

Give you a head node of the single linked list. Please judge whether the linked list is a palindrome linked list. If yes, return true; Otherwise, false is returned

Example:
  input: head = [1,2,2,1]
  output: true

Steps:

  • The linked list type for problem solving is single linked list

  • Idea:

    • Throw the linked list into the array with the help of the array
    • Set the front and rear pointers. The front and rear pointers should be the same. If they are different, they are not palindromes
    • If the loop ends without returning false, it is a palindrome
  • Boundary conditions:

    • Inconsistent front and rear pointers
    • End of cycle
var isPalindrome = function (head) {
  const res = []
  while (head) {
    res.push(head.val);
    head = head.next
  }
  let pre = 0;
  let last = res.length - 1;
  while (pre < last) {
    if (res[pre] !== res[last]) return false;
    pre++;
    last--;
  }
  return true
}

8,Intersecting linked list

Here are the head nodes headA and headB of the two single linked lists. Please find and return the starting node where the two single linked lists intersect. The topic data ensures that there are no rings in the whole chain structure.

be careful:

  • After the function returns the result, the linked list must maintain its original structure (the new linked list needs to be copied)
  • If two linked lists have no intersection, null is returned
  • The program shall be full of O(n) time complexity and only use O(1) memory

Example:
    Input: intersectVal = 4, listA = [1,2,3,4,5], listB = [6,7,4,5], skipA = 3, skipB = 2   // In A, there are 3 nodes before the intersection node; In B, there are 2 nodes before the intersection node
    Output: Intersected at '4'  // The value of the intersection node is 4 (note that if two linked lists intersect, it cannot be 0)

Steps:

  • The linked list type for problem solving is single linked list
  • Idea:
    • As above, find the height difference of AB linked list and eliminate it. The length after the known intersection point must be equal
    • AB double pointers advance at the same time. When the pointer traversal of the short linked list B is completed, the length difference of the double pointers is just the length difference of the double linked list. Point the B pointer to the head node of the A linked list, and follow the A pointer to traverse again until the pointer traversal of A is completed
    • Similarly, if the A pointer points to the head node of the B linked list, and the B pointer moves forward, the height difference of the linked list is eliminated

  • Boundary conditions:
    • Switch to point to linked list when pointer points to null
    • AB linked list values are equal
var getIntersectionNode = function (headA, headB) {
  if (!headA || !headB) return null;
  let pA = headA;
  let pB = headB;
  while (pA !== pB) {
    pA = pA !== null ? pA.next : headB;
    pB = pB !== null ? pB.next : headA;
  }
  return pA;
}

9,List summation

Given two integers represented by a linked list, each node contains a digit. These digits are stored in reverse, that is, a digit is arranged at the head of the linked list. Write a function to sum the two integers and return the result in the form of a linked list

Example:
  Input:(7 -> 1 -> 6) + (5 -> 9 -> 2),617 + 295
  Output: 2 -> 1 -> 9,I.e. 912

Steps:

  • The linked list type for problem solving is single linked list

  • Idea:

    • The output is a new linked list, so you need to create a linked list
    • Because of the reverse storage, the linked list is calculated from the single digit, and if it is greater than ten, it is carried
    • For carry, first consider "carry" to store each carry, and the remainder is stored in the created node
  • Boundary conditions:

    • When the double linked list points to null, the traversal is completed
    • The traversal is completed. If the carry is not 0, it needs to advance one bit
const addTwoNumbers = function (l1, l2) {
  // sentry
  let preHead = new ListNode(0)
  let carry = 0;
  let pre = preHead;
  while (l1 || l2) {
    let sum = 0;
    if (l1) {
      sum += l1.val
      l1 = l1.next
    }
    if (l2) {
      sum += l2.val
      l2 = l2.next
    }
    sum += carry
    carry = Math.floor(sum / 10)
    pre.next = new ListNode(sum % 10)
    pre = pre.next
  }
  if (carry > 0) {
    pre.next = new ListNode(carry)
    pre = pre.next
  }
  return preHead.next
}
Advanced: think about how to solve the problem if these digits are stored forward?
  Input:(6 -> 1 -> 7) + (2 -> 9 -> 5),617 + 295
  Output: 9 -> 1 -> 2,I.e. 912

Tags: Javascript Next.js

Posted by deerly on Tue, 26 Jul 2022 21:45:41 +0530