Will list a literature pointer speed problem-solving skills

Foreword

Above, we learn the basic concepts in detail the list of advantages and disadvantages, but also take you step by step progressive approach to learning the skills flipping the list, this one we look at another list of problem-solving skills: speed pointer.

Probability speed pointer appears during an interview is also great, but also be sure to grasp a point, this paper summarizes the common market, the speed of the pointer problem-solving skills, I believe after reading this kind of problem can Shoudaoqinlai. This article will describe in detail how to solve the problem with the following two categories pointer speed

  1. Find / delete the first K nodes
  2. Solution relevant issues concerning the list of ring

Find / delete the first K nodes

One small scale chopper

LeetCode 876: Given a non-empty list with a single head of the first node, an intermediate node returns the list. If there are two intermediate nodes, the second intermediate node is returned.

A solution to know the list of intermediate nodes, first of all we need to know the length of the list when it comes to the length of the list of what we think, we remember the above mentioned sentinel node list can be saved in the length of it, so directly from the head the successor node traversing the linked list length / 2 times to find an intermediate node. Why is the intermediate node list Length / 2, we carefully analyze

  1. If the chain length is odd: head ---> 1 ---> 2 ---> 3 ---> 4 ---> 5, traversing from 1 5/2 = 2 (rounded) times, arriving 3 3 is indeed an intermediate node
  2. If the chain length is an even number: head ---> 1 ---> 2 ---> 3 ---> 4 ---> 5 ---> 6, from traversing 6/2 1 = 3 times, arrival 4,4 indeed a second node of the intermediate node

Voiceover: Multi painting map, for example, can see the essence of things!

After sentinel node length handy, this simple way, directly on the code

public Node findMiddleNode() {
    Node tmp = head.next;
    int middleLength = length / 2;
    while (middleLength > 0) {
        tmp = tmp.next;
        middleLength--;
    }
    return tmp;
}
复制代码

Solution two

If the sentinel node is not defined in the length of it, then again to traverse the list to get the list length (defined as the length), and then start from scratch node traversal length / 2 times is the intermediate node

public Node findMiddleNodeWithoutHead() {
    Node tmp = head.next;
    int length = 1;
    // 选遍历一遍拿到链表长度
    while (tmp.next != null) {
        tmp = tmp.next;
        length++;
    }

    // 再遍历一遍拿到链表中间结点
    tmp = head.next;
    int middleLength = length / 2;
    while (middleLength > 0) {
        tmp = tmp.next;
        middleLength--;
    }
    return tmp;
}
复制代码

Solution three

Solution two due to traverse the list twice, it is not so efficient, that can only traverse a linked list of intermediate nodes can get it.

Here on the introduction of the speed of our hands, and there are three steps 1, while the speed of the pointer points to successor node head 2, take a step slow hands, fast hands take two steps 3, continue to repeat step 2, and when to stop it, this depending on the length of the list is odd or even

  • If the chain length is odd, when fast.next = null, slow intermediate node

  • If the chain length is an even number, when fast = null, slow intermediate node

    From the above analysis: When fast = null or fast.next = null, in this case the node is the slow Desired intermediate node, or continuously repeating steps 2, got the idea, the code is simple to achieve

/**
 * 使用快慢指针查找找到中间结点
 * @return
 */
public Node findMiddleNodeWithSlowFastPointer() {
    Node slow = head.next;
    Node fast = head.next;
    while (fast != null && fast.next != null) {
        // 快指针走两步
        fast = fast.next.next;
        // 慢指针走一步
        slow = slow.next;
    }
    // 此时的 slow 结点即为哨兵结点
    return slow;
}
复制代码

With the basis of the above, we can now look at another big difficulty, look at this question below

A list input, the output of the inverse of the k th node in the linked list. For example the list is head -> 1 -> 2 -> 3 -> 4 -> 5. A reciprocal third node (i.e., node value of 3)

Analysis: We know that if required the k-th node order is quite simple, start from head to traverse k times can, if required k-th node in reverse order, the conventional approach is to iterate over the list order, to get the list length, and then traverse the list -k length of time can be, so to traverse the list twice, not so efficient, how to traverse only once, or whether talking with our speed indicator solution

  1. Let's head speed pointer both point successor node
  2. Fast forward pointer k- 1 steps, walks to the k-th node
  3. While the speed of the pointer back step, this step is repeated until the pointer quickly went to the end node, the node that is slow in this case we are looking for the k-th node reverse

Note: Note borderline case: K is greater than the length of the list, such an anomaly should Throws

public Node findKthToTail(int k) throws Exception {
    Node slow = head.next;
    Node fast = head.next;

    // 快指针先移到第k个结点
    int tmpK = k - 1;
    while (tmpK > 0 && fast != null) {
        fast = fast.next;
        tmpK--;
    }
    // 临界条件:k大于链表长度
    if (fast == null) {
        throw new Exception("K结点不存在异常");
    }
    // slow 和 fast 同时往后移,直到 fast 走到尾结点
    while (fast.next != null) {
        slow = slow.next;
        fast = fast.next;
    }
    return slow;
}
复制代码

We know how to find reverse the k-th node, look at this question below

Given a singly-linked list, a design algorithm K chain rotation to the right positions. Example: Given head-> 1-> 2-> 3-> 4-> 5-> NULL, K = 3, for the right-handed after head-> 3-> 4-> 5 -> 1-> 2 -> NULL

Analysis: This question is actually seeking reverse the K-th position of a deformation of the main ideas are as follows

  • First find the penultimate K + 1 nodes, successor node of this node is the penultimate K nodes
  • The penultimate node K + 1 is set to null successor node
  • The successor node is set to the reciprocal of the head obtained above the K-th node, the original successor node to the end node successor node of the original head

public void reversedKthToTail(int k) throws Exception {
    // 直接调已实现的 寻找倒序k个结点的方法,这里是 k+1
    Node KPreNode = findKthToTail(k+1);
    // 倒数第 K 个结点
    Node kNode = KPreNode.next;
    Node headNext = head.next;

    KPreNode.next = null;
    head.next = kNode;

    // 寻找尾结点
    Node tmp = kNode;
    while (tmp.next != null) {
        tmp = tmp.next;
    }
    // 尾结点的后继结点设置为原 head 的后继结点
    tmp.next = headNext;
}
复制代码

With the groundwork two questions above, I believe that following this question is not difficult, limited space relationship, not to proceed here, you can see for yourself

Enter a list, remove the reciprocal k-th node in the linked list

Small scale chopper bis

Analyzing two single chain intersect and find the first intersection, requires space complexity O (1). As shown: If the two lists intersect, 5 for the first point of intersection of two intersecting list

VO: If there is no space complexity of O (1) limit, in fact, a variety of solution A is 1 traverse the list, the list of all the nodes 1 are put in a set, again traverse the list 2, each traversing a node, it is determined whether the node set, if it is found in this node in the set, then the first node is a node list intersects

Analysis: First, we need to understand that due to the nature of the list itself, if there is a junction intersection, then all the nodes after the intersection nodes are common to both lists, that is the main difference between the length of two lists at the intersection length before the junction node, then we have the following ideas

1, if the chain length is not defined, then we get the two lists to traverse the length of the two lists, respectively, assuming L1, L2 (L1> = L2), the definition of p1, p2 are each linked list head pointer pointing to the node, then p1 go on ahead L1 - L2 step. This step ensures that p1, p2 pointer to the intersection node (if any) as close.

2 and p1, p2 constantly traversed back, each step, determining a respective side edge traversing node is equal, if these two are equal is the intersection node list

public static Node detectCommonNode(LinkedList list1, LinkedList list2) {
    int length1 = 0;        // 链表 list1 的长度
    int length2 = 0;        // 链表 list2 的长度

    Node p1 = list1.head;
    Node p2 = list2.head;

    while (p1.next != null) {
        length1++;
        p1 = p1.next;
    }

    while (p2.next != null) {
        length2++;
        p2 = p2.next;
    }

    p1 = list1.head;
    p2 = list2.head;

    // p1 或 p2 前进 |length1-length2| 步
    if (length1 >= length2) {
        int diffLength = length1-length2;
        while (diffLength > 0) {
            p1 = p1.next;
            diffLength--;
        }
    } else {
        int diffLength = length2-length1;
        while (diffLength > 0) {
            p2 = p2.next;
            diffLength--;
        }
    }
    // p1,p2分别往后遍历,边遍历边比较,如果相等,即为第一个相交结点
    while (p1 != null && p2.next != null) {
        p1 = p1.next;
        p2 = p2.next;
        if (p1.data == p2.data) {
            // p1,p2 都为相交结点,返回 p1 或 p2
            return p1;
        }
    }
    // 没有相交结点,返回空指针
    return null;
}
复制代码

Advanced

Next we look at how to use the list to determine whether the speed of the pointer A ring, which is the most common use of pointer speed

Determining whether there is a ring list, and if so, to find the entrance position of the ring (FIG. 2 below), the required space complexity is O (1)

First we look at the list if there is a ring what laws, if traversing from the head node, then the pointer will traverse the circle in the above loop, so we can define separately pointer speed, pointer slow step, walking two fast pointer step, since the last speed pointer always will be around during traversal in the circle in, and the speed of the pointer each traversal step is not the same, so they are in there constantly circle process will be met, just as 5000 meters, one run fast, one slow fast, run fast people will catch up the slower runners (ie rings).

I do not understand? Then we prove it simple

1, if the pointer quickly from a difference of a slow node pointer, then the next iteration step by the slow pointer, the pointer quickly take two steps, encounter

2, if the difference between the two nodes pointer quickly from slow pointer, then the next iteration step by the slow pointer, the pointer quickly take two steps, a difference of a node, converted into the above 1

3, if the pointer quickly from a difference of N nodes slow pointer (N greater than 2), the next step Traversal slow down pointer, the pointer quickly take two steps, so the difference of N + 1-2 = N-1 nodes, found yet, the phase difference from the node N becomes N-1, reduced! Continuously traversing, the phase difference node will continue to shrink, shrink when N is 2, i.e., into the above Step 2, to thereby obtain certificates, if the ring, the pointer will meet speed!

** voiceover: If the pointer to go a step slow, not fast pointer to go two steps, but greater than two steps, there will be any problems, we can consider **

/**
 * 判断是否有环,返回快慢指针相遇结点,否则返回空指针
 */
public Node detectCrossNode() {
    Node slow = head;
    Node fast = head;

    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
        
        if (fast == null) {
            return null;
        }

        if (slow.data == fast.data) {
            return slow;
        }
    }
    return null;
}
复制代码

Analyzing a cycloalkyl why meet node to return, instead it returns true or false. Because the title there is a requirement to determine the position of the inlet ring, is laying the groundwork for this, take a look at how to find the ring entrance, tricky analysis

7 is assumed to meet the above figure is the speed of the node pointer, the pointer is easy to see slow walk step L + S, the pointer quickly went fairly slow pointer quickly, which in addition to L + S gone step, but also in additional ring Lane around the n-turns, so that fast pointer left L + S + nR step (length R is a drawing of the ring), and we know that every traversal time, slow pointer take a step, fast pointer took two steps, so that fast pointer down slow pointer is twice the distance, i.e. 2 (L + S) = L + S + nR, i.e. L + S = nR

  • When n = 1, then when L + S = R, traversing from the meeting point went from 7 ring entry point 2 is R - S = L, just the entry node of the ring, while the ring head entry point 2 is also exactly the distance L, so long as the head is defined in a node pointer, in the meeting point (7) further defines a pointer, two pointers while traversing each step, inevitably encounter the inlet position of the ring 2
  • When n> 1, L + S = nR, i.e. L = nR - S, nR- S appreciated how? Can be seen as a pointer from the node 7, to go circle n, S backoff step, just at this time point ring entry position , that is to say if the head pointer to a set (defined as P1), a pointer to a separate 7 (defined as P2), continuously traversed, p2 go nR-S (i.e., the inlet position of the ring), also happens to come here p1 (p1 case go nR-S = L step, just the position of the inlet ring) that the two meet!

In summary, to find the entry node, simply define two pointers, a pointer to the head, a pointer to point to the meeting point speed, and then continues to traverse the two pointers (simultaneously take a step), if they point to the same when the node i.e. the node is an entry ring

public Node getRingEntryNode() {
        // 获取快慢指针相遇结点
        Node crossNode = detectCrossNode();

        // 如果没有相遇点,则没有环
        if (crossNode == null) {
            return null;
        }

        // 分别定义两个指针,一个指向头结点,一个指向相交结点
        Node tmp1 = head;
        Node tmp2 = crossNode;

        // 两者相遇点即为环的入口结点
        while (tmp1.data != tmp2.data) {
            tmp1 = tmp1.next;
            tmp2 = tmp2.next;
        }
        return tmp1;
    }
复制代码

Questions: Know entry node ring, how to find the length of the loop?

to sum up

This article summarizes the speed pointer list common problem-solving skills, summarize the two types of problem: find the K-th node, and determines its entry ring node, plus the above list mentioned inversion techniques, two interview categories are very popular test sites, others face questions mostly deformed in these two categories, we established a good knock the code again, if needed, the text code can be in my github address download

reference

More basic knowledge of computer algorithms + + Java and other articles, I welcome attention to the micro-channel public number oh.

Guess you like

Origin juejin.im/post/5e107727e51d4540ec4f433a