Data structure questions in front end interview

Time:2021-5-13

1、 Single linked list flipping (leetcode 206)

1. Iterative method

var reverseList = function(head) {
    if(!head || !head.next){
        return head;
    }else{
        //Initialize prev and curr first
        var prev = null;
        var curr = head;
        //Continuously point the next pointer of the latter node to the precursor node until the node is null, which means the end of the linked list. At this time, prev is the last node of the linked list
        while(curr){
            var next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        head = prev;
        return head;
    }
}

2. Tail recursive method (the idea is the same as iterative method, except that the recursive scheme is added at the end of the function)

var reverseList = function(head) {
    if(!head || !head.next){
        return head;
    }else{
        head = reverse(null, head);
        return head;
    }
}

function reverse(prev, curr){
    if(!curr) return prev;
    var next = curr.next;
    curr.next = prev;
    //Note that there must be a return value, because there is head = reverse (null, head). If there is no return value, head will be undefined
    return reverse(curr, next);
}

3.Recursive method(focus)
(1) Function stack
Data structure questions in front end interview

(2) Implementation code:

var reverseList = function(head) {
    if(!head || !head.next){
        return head;
    }else{
        //First move the head to the penultimate node and next to the penultimate node
        var next = head.next;
        //Get the last node
        var reverseHead = reverseList(next);
        //Recursion from the back forward, pointing the next pointer of the next node to its previous node (that is, the head node)
        next.next = head;
        //Set the next pointer of the head node to null
        head.next = null;
        return reverseHead;
        //When a function is finished here, if the previously called function is not finished, it will continue to execute the previous function until all functions are finished
        //Use the execution sequence of JS main thread's function stack to understand that only after a function is executed, the function will be out of the stack (LIFO)
    }
};

2、 Single linked list to judge whether there is a ring (leetcode 141)

1. Marking method: add a mark to each convenient node, traverse the linked list, and prove that there are links in the linked list when the next node has been marked

//Mark method, add mark bit to each traversed node, traverse the linked list, when the next node has been marked, it is proved that the single linked list has a ring
function hasCycle(head){
    while(head){
        if(head.flag) return true;
        head.flag = true;
        head = head.next;
    }
    return false;
}

2.Double finger needling(emphasis): also known asFast slow pointer methodThe starting position of the fast pointer is the same as that of the slow pointer,A fast pointer moves twice as fast as a slow pointerIf two pointers meet in the process of traversal, it means that there are rings in the linked list.

//Double finger Needling: the fast pointer takes two steps at a time, and the full pointer takes one step at a time. If there is a link in the list, the two pointers will definitely meet
var hasCycle = function(head) {
    if(!head || !head.next){
        return false;
    }else{
        var fast = head;
        var slow = head;
        //If one of fast and fast. Next is null, there is no need to loop
        while(fast && fast.next){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                return true;
            }
        }
        return false;
    }
};

3、 Entry of single linked list to find loop (leetcode 142)

1.Double finger needling: speed pointer plus extra slow pointer
(1) How to solve the problem:
Data structure questions in front end interview

From the above mathematical formula, it can be concluded that when the first slow pointer and the newly created slow pointermeanwhileStart traversing backwards(Slow pointer 1 traverses from where it meets fast pointer, and slow pointer 2 traverses from head), theyThe meeting place must be at the entrance node of the ring

(2) Code implementation:

var detectCycle = function(head){
    if(!head || !head.next){
        return null;
    }else{
        //First, use the double finger needle method to find out the position where the fast and slow hands meet
        //Note that the fast and slow here must start from the head to ensure that the new slow pointer starting from the head can meet the old slow pointer at the entry point of the ring
        var fast = head;
        var slow = head;
        while(fast && fast.next){
            fast = fast.next.next;
            slow = slow.next;
            if(fast === slow){
                //Define a slow pointer starting from the head and continuously traverse backward. The position where two slow pointers meet is the entrance position of the ring
                var slow2 = head;
                while(slow !== slow2){
                    slow = slow.next;
                    slow2 = slow2.next;
                }
                return slow2;
            }
        }
        return null;
    }
};

4、 Find the intersection node of two linked lists (leetcode 160)

1. Brute force traversal marking method (not recommended): time complexity O (n), space complexity O (n) (to create n variables to record traversal node label)

var getIntersectionNode = function(headA, headB) {
    //First traverse the A-list and add tags to each node
    while(headA) {
        headA.flag = true
        headA = headA.next
    }
    //Then traverse the linked list B to check whether there are any tags in the linked list B. if there are, it is proved that the two linked lists a and B intersect and the node is returned. If not, they do not intersect
    //Time complexity O (n), space complexity O (n)
    //Not recommended
    while(headB) {
        if (headB.flag) return headB
        headB = headB.next
    }
    return null
};

2.Double finger needling:recommend(time complexity O (n), space complexity O (n))

(1) Solution: if there is an intersection between two linked lists, the two linked lists start to traverse from the beginning,When traversing to the last node, start from the head of another linked list, then the two pointers must meet at the intersection of the two linked lists, because they all follow the same path.

(2) Code implementation:

//Time complexity O (n), space complexity O (1)
var getIntersectionNode = function(headA, headB){
    var A = headA;
    var B = headB;
    while(A !== B){
        A = A !== null? A.next: headB;
        B = B !== null? B.next: headA;
    }
    return A;
};

5、 Find intermediate node in single linked list (leetcode 876)

1. Double finger needling (fast and slow pointer method): it is also necessary here that the fast and slow pointers start from the head node and traverse backwards.

//Using the fast and slow pointer method, when the fast pointer goes to the last node, the slow pointer just goes to the middle node
var middleNode = function(head){
    var slow = head;
    var fast = head;
    while(fast && fast.next){
        fast = fast.next.next;
        slow = slow.next;
    }
    return slow;
};

6、 Merge two ascending linked lists (leetcode 21)

1. Double finger needling method
(1) Solution: open up a new space to create a new list, and thenCompare the sizes of L1 and L2 linked lists in turn, and take the smaller value as the node in front of the new linked list L3,Traverse the two linked lists L1 and L2 in turn untilWhen one of the linked lists is emptyBecause the rest of the other linked list is also in ascending order, and it must be larger than the values of all nodes in L3, soConnect the rest directly after L3That’s it.

var mergeTwoLists = function(l1, l2) {
    //If one of the two linked lists is empty at the beginning, another linked list will be returned
    if(l1 == null){
        return l2;
    }
    if(l2 == null){
        return l1;
    }
    //Open up a new space to represent a new empty list (no parameters are passed in)
    var l3 = new ListNode();
    //At the beginning, pre and L3 point to the same space (shallow copy). Pre represents the latest node traversed in L3
    var pre = l3;
    while(l1 && l2){
        if(l1.val < l2.val){
            pre.next = l1;
            l1 = l1.next;
        }else{
            pre.next = l2;
            l2 = l2.next;
        }
        //L3 every time a new node is added, the pre has to go one step further
        pre = pre.next;
    }
    //If one of the linked lists is empty, directly connect the rest of the other linked list to the back of L3
    pre.next = l1 != null? l1: l2;
    return l3.next;
};

2.Recursive method(recommended)
(1) Solution: when you encounter recursion problems, it’s easy to understand with the idea of function stack.
Data structure questions in front end interview

(2) Code implementation:

//Recursive functions don't really end until return
var mergeTwoLists = function(l1, l2) {
    if(l1 === null){
        return l2;
    }
    if(l2 === null){
        return l1;
    }
    if(l1.val < l2.val){
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    }else{
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
};

7、 In addition, attach the constructor of the linked list

function ListCode(val){
    this.val = val;
    this.next = null;
}