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:
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:
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 .
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 .
2. Use the k + 1
first element as a head
recursive call reverseKGroup
function .
3. Connect the results of the above two processes .
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; }
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:
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:
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!