Recursive thinking: a set of k reversal linked lists

The previous article "Recursively reverse a part of a linked list" talked about how to reverse a part of a linked list recursively. Some readers asked how to reverse a linked list iteratively. The problem that this article solves also requires the function of reversing the linked list. We might as well use Iterative way to solve.

This article is to solve "K a set of reverse linked lists", it is not difficult to understand:

9069c84b9d84a1fff9505c320923ca9f.jpg

This problem is often seen in the face-to-face, and the difficulty on LeetCode is Hard, is it really that difficult?

The algorithmic problem of basic data structure is actually not difficult, as long as it combines the characteristics of a little bit of disassembly and analysis, it is generally not difficult. Let's disassemble this problem.

One, analyze the problem

First of all, the framework thinking of learning data structure mentioned above, linked list is a data structure with both recursive and iterative properties. If you think about it carefully, you can find that this problem is recursive .

What is the recursive nature? To understand directly above, for example, we call this linked list  reverseKGroup(head, 2), that is, a set of reverse linked lists with 2 nodes:

87474e9876872f2ac883967829a5febf.jpeg

If I try to reverse the first 2 nodes, what about the latter nodes? The following nodes are also a linked list, and the scale (length) is smaller than the original linked list, which is called a sub-problem .

d1a55c987b01c14098e432d2256d84bf.jpeg

We can directly call recursively  reverseKGroup(cur, 2), because the structure of the sub-problem is exactly the same as the original problem. This is the so-called recursive nature.

After discovering the recursive nature, you can get a rough algorithm flow:

1. Reverse  head the  k first element first .

6bd70a66c7007ea214c6e51dfe8803ce.jpeg

2. Use the  k + 1 first element as a  head recursive call  reverseKGroup function .

7645f5d8d9d21e08f61a4b79d3f708ec.jpeg

3. Connect the results of the above two processes .

86096091d69d0d434bb105688422ab34.jpeg

This is the overall idea. The last point worth noting is that recursive functions have a base case. What is the problem with this?

The title says, if the last element is not enough  k , it will remain unchanged. This is the base case, which will be reflected in the code later.

Two, code implementation

First, we need to implement a  reverse function to reverse the elements within an interval. Before that, let's simplify it again. Given the head node of the linked list, how to reverse the entire linked list?

// Reverse the linked list with a as the head node
ListNode reverse(ListNode a) {
    ListNode pre, cur, nxt;
    pre = null; cur = a; nxt = a;
    while (cur != null) {
        nxt = cur.next;
        // Reverse node by node
        cur.next = pre;
        // Update pointer position
        pre = cur;
        cur = nxt;
    }
    // Return the head node after reversal
    return pre;
}

2de178ab32b377055a620a7b4a3c44db.gif

This time iterative thinking is used to realize it, and it should be easy to understand with animation.

"Reversed to  a as the head node list" is actually a "reversal  a to the junction between the null", so if you let 'reverse  a to  b the junction point between ", would you?

Whenever change the function signature, and put the above code  null changed  b to:

/** Reverse the elements of the interval [a, b), note that the left is closed and the right is open */
ListNode reverse(ListNode a, ListNode b) {
    ListNode pre, cur, nxt;
    pre = null; cur = a; nxt = a;
    // Just change the condition of while termination
    while (cur != b) {
        nxt = cur.next;
        cur.next = pre;
        pre = cur;
        cur = nxt;
    }
    // Return the head node after reversal
    return pre;
}

PS: I have written more than 100 original articles carefully , and I have hand-in-hand brushed 200 buckle questions, all of which are published in  labuladong's algorithm cheat sheet , which is continuously updated . It is recommended to collect, brush the questions in the order of my articles , master various algorithm routines, and cast them into the sea of ​​questions.

Now that we iteratively implement the function of reversing part of the linked list, then we reverseKGroup can write the function according to the previous logic  :

ListNode reverseKGroup(ListNode head, int k) {
    if (head == null) return null;
    // The interval (a, b) contains k elements to be reversed
    ListNode a, b;
    a = b = head;
    for (int i = 0; i < k; i++) {
        // less than k, no need to reverse, base case
        if (b == null) return head;
        b = b.next;
    }
    // Reverse the first k elements
    ListNode newHead = reverse(a, b);
    // Recursively reverse the subsequent linked lists and connect them
    a.next = reverseKGroup(b, k);
    return newHead;
}

Explain  for a few lines of code after the loop. Note that the  reverse function is to reverse the interval  [a, b), so the situation is like this:

093a3cf2d077e781d6bf30415cdd5af7.jpeg

The recursion part is not expanded. This result is after the entire function is recursively completed, which is fully in line with the meaning of the question:

06d9276ead86fe342f3e464609a708ca.jpeg

Three, one last sentence

In terms of reading volume, not many people have read articles about algorithms related to basic data structures. I want to say that this is a disadvantage.

Everyone likes to look at issues related to dynamic programming, probably because interviews are very common, but as far as I understand it, many algorithm ideas are derived from data structures. One of the famous works of our official account, "Learning the framework of data structure thinking" mentioned that all rules, backtracking, and divide-and-conquer algorithms are actually tree traversals. The structure of a tree is not just a multi-linked list. ? You can deal with basic data structure problems, and solving general algorithm problems shouldn't be too much trouble.

So how to decompose the problem and discover the recursive nature? This can only be practiced more, maybe I can write an article to discuss it later, this article will stop here, I hope it will be helpful to everyone!


Guess you like

Origin blog.51cto.com/15064450/2570804