Like attention, no more lost, your support means a lot to me!
š„ Hi, I’m Chouchou. GitHub Ā· Android-Notebook has been included in this article. Welcome to grow up with Chouchou Peng. (Contact information at GitHub)
preface
- Questions related to linked lists are frequently asked in interviews and are often the basis for solving other complex problems.
- In this article, I will comb through the problems & solutions of linked list problems. Please be sure to like and follow if you can help, it really means a lot to me.
series
- The algorithm of interview questions | problems summary list”
- The algorithm problem of intersection and cyclization interview questions | chain table”
- The interview questions | back algorithm problem solving framework
- Interview questions | and check the data structure set & joint – search algorithms,
- The interview questions | binary tree data structure foundation”
Extension of the article
- Algorithm of interview questions | buildings with eggs (from Google interview questions)
Delete the linked list node |
Hint & problem solving |
---|---|
203. Remove linked list elements Remove Linked List Elements |
“Antithesis” |
237. Delete a node from a linked list Delete Node in a Linked List |
“Antithesis” |
Delete the penultimate node of the linked list Remove Nth Node From End of List |
“Antithesis” |
86. Separate linked lists Partition List |
“Antithesis” |
328. Odd-even linked lists Odd Even Linked List |
“Antithesis” |
83. Delete duplicate elements from sorted linked lists Remove Duplicates from Sorted List |
|
Delete duplicate element II from sorted list Remove Duplicates from Sorted List II |
|
725. Separated linked lists Split Linked List in Parts |
|
(Extended) 0876. Intermediate node of a linked list Middle of the Linked List |
“Antithesis” |
Reverse a linked list |
Hint & problem solving |
---|---|
206. Reverse linked lists Reverse Linked List |
“Antithesis” |
92. Reverse linked list II Reverse Linked List II |
“Antithesis” |
234. Palindrome linked list Palindrome Linked List |
“Antithesis” |
25. Flip linked lists in groups of K Reverse Nodes in k-Group |
Merge ordered linked lists |
Hint & problem solving |
---|---|
21. Merge two ordered lists Merge Two Sorted Lists |
“Antithesis” |
Merge K ascending linked lists Merge k Sorted Lists |
“Antithesis” |
Sorting list |
Hint & problem solving |
---|---|
Insert sort on linked lists Insertion Sort List |
“Antithesis” |
148. Sort linked lists Sort List |
“Antithesis” |
Circular linked list |
Hint & problem solving |
---|---|
160. Intersecting linked lists Intersection of Two Linked Lists |
“Antithesis” |
141. Circular linked lists Linked List Cycle |
“Antithesis” |
142. Circular linked List II Linked List Cycle II |
“Antithesis” |
61. Rotate linked lists Rotate List |
“Antithesis” |
other |
Hint & problem solving |
---|---|
Swap nodes in a linked list in pairs Swap Nodes in Pairs |
|
143. Rearrange linked lists Reorder List |
|
138. Copy linked lists with random Pointers Copy List with Random Pointer |
|
380. Constant time inserts, deletes, and retrieves random elements Insert Delete GetRandom O(1) |
|
381. O(1) Time to insert, remove and get random elements – allow repetition Insert Delete GetRandom O(1) – Duplicates allowed |
|
707. Design linked lists Design Linked List |
|
430. Flat multilevel bidirectional linked lists Flatten a Multilevel Doubly Linked List |
|
817. List components Linked List Components |
“Antithesis” |
directory
1. An overview of the
1.1 Definition of linked lists
Linked list is a common basic data structure, is a linear list. Unlike a sequential list, each node in a linked list is not stored sequentially, but is pointed to the next node through the node’s pointer field.
1.2 Advantages and disadvantages of linked lists
contrast | advantages | disadvantages |
---|---|---|
Memory management | Make full use of computer memory space, more flexible allocation of memory space | Pointer fields increase memory consumption |
Operational efficiency | Can be in Delete or add nodes within time (if the precursor node is known) |
Lost the random access feature of the array, the query corresponding to the location of the node needed time |
Data capacity | The memory must be allocated in advance. If the memory capacity is insufficient, the capacity must be expanded | No pre-allocated memory space is required, and no expansion is required |
Access performance | / | CPU caching rows does not improve efficiency |
1.3 Types of linked lists
Single, double, circular, and static lists
2. Delete linked list nodes
When deleting a linked list node, considering that it may be the first node of the list to be deleted (no precursor node), a sentinel node can be added for coding convenience. Among them, in the problem of deleting the penultimate node of the linked list, using fast and slow Pointers to find the penultimate node in a scan is an important programming skill.
237. Delete Node in a Linked ListĀ “Antithesis”
Remove Linked List ElementsĀ “Antithesis”
Class Solution {fun removeElements(head: ListNode? , `val`: Int): ListNode? {// val sentinel = ListNode(-1). Next = head var pre = sentinel var cur: ListNode? = sentinel while (null ! = cur) {if (' val '== cur.' val ') {// Remove pre. Next = cur.next} else {pre = cur} cur = cur.next} return sentinel Class Solution {fun removeElements(head: ListNode? , `val`: Int): ListNode? {// val sentinel = ListNode(-1). Next = head var pre = sentinel var cur: ListNode? = sentinel while (null ! = cur) {val removeNode = if (' val '== cur.' val ') {// Remove pre. Next = cur.next cur else {pre = cur null} cur = cur.next if (null ! = removeNode) { removeNode.next = null } } return sentinel.next } }Copy the code
Remove the Nth Node From End of ListĀ “Antithesis”
Given a linked list, delete the NTH last node of the list and return the first node of the list.
class Solution { fun removeNthFromEnd(head: ListNode, n: Int): ListNode? {// val sentinel = ListNode(-1) sentinel. Next = head var fast: ListNode? = sentinel var slow: ListNode? = sentinel for (index in 0 until n) { fast = fast!! .next} // Find the last KTH node while (null! = fast!! .next) { fast = fast.next slow = slow!! .next } slow!! .next = slow.next!! .next return sentinel.next } }Copy the code
Complexity analysis:
- Time complexity: Scan each node once, and the time complexity is O(n)O(n)O(n)
- Space complexity: Constant level variables are used and the space complexity is O(1)O(1)O(1)
In a similar way, the Middle of the Linked List is found by using fast and slow Pointers:
class Solution { fun middleNode(head: ListNode?) : ListNode? { if (null == head || null == head.next) { return head } var fast = head var slow = head while (null ! = fast && null ! = fast.next) { fast = fast.next!! .next slow = slow!! .next } return slow } }Copy the code
86. Partition List separates linked listsĀ “Antithesis”
Deletes all nodes in the linked list that are equal to the given value val.
To separate a linked list, you must first remove a node greater than or equal to val from the original list and then join the two lists.
class Solution { fun partition(head: ListNode? , x: Int): ListNode? {if (null == head) {return null} val sentinel = ListNode(-1) sentinel.next = head var pre = sentinel // second linked list var bigHead : ListNode? = null var bigRear = bigHead var cur = head while (null ! If (cur. 'val' >= x) { Next if(null == bigHead){bigHead = cur bigRear = cur}else{bigRear!! .next = cur bigRear = cur}} else {pre = cur} if (null == cur.next) {// splice. pre = bigHead bigRear? .next = null break } cur = cur.next } return sentinel.next } }Copy the code
Complexity analysis:
- Time complexity: Scan each node once, and the time complexity is O(n)O(n)O(n)
- Space complexity: Constant level variables are used and the space complexity is O(1)O(1)O(1)
328. Odd Even Linked ListĀ “Antithesis”
An odd-even list consists of placing odd nodes in one list, even nodes in another list, and then attaching even nodes to the end of the odd-even list
class Solution { fun oddEvenList(head: ListNode?) : ListNode? { if (null == head) { return null } var odd: ListNode = head var even = head.next val evenHead = even while (null ! = even && null ! = even.next) {// Even.next = even.next odd = odd.next!! Next = even.next = even.next = even.next = even.next = even.next = evenHeadCopy the code
Delete Duplicates from Sorted List
Delete Duplicates from Sorted List II. Delete Duplicates from Sorted List II
3. Reverse the list
Reverse linked list questions appear very frequently in the interview, I believe that students who have several interview experience will agree with this point of view. Here, I’ve identified four reverse linked list problems, ranging from easy to hard.
206. Reverse Linked ListĀ “Antithesis”
Reverse a single linked list.
Solution 1: Recursion
class Solution { fun reverseList(head: ListNode?) : ListNode? { if(null == head || null == head.next){ return head } val prefix = reverseList(head.next) head.next.next = head head.next = null return prefix } }Copy the code
Complexity analysis:
- Time complexity: Scan each node once, and the time complexity is O(n)O(n)O(n)
- Space complexity: The recursive stack is used and the space complexity is O(n)O(n)O(n)
Solution 2: Iteration
class Solution { fun reverseList(head: ListNode?) : ListNode? { var cur: ListNode? = head var headP: ListNode? = null while (null ! = cur) { val tmp = cur.next cur.next = headP headP = cur cur = tmp } return headP } }Copy the code
Complexity analysis:
- Time complexity: Scan each node once, and the time complexity is O(n)O(n)O(n)
- Space complexity: Constant level variables are used and the space complexity is O(1)O(1)O(1)
92. Reverse Linked List IIĀ “Antithesis”
Given a linked list, rotate the list by moving each node of the list k positions to the right, where k is non-negative.
class Solution { fun reverseBetween(head: ListNode? , m: Int, n: Int): ListNode? {if (null = = head | | null = = head. The next) {return head} / / sentinel node val sentinel = ListNode (1) sentinel. Next = head var rear = sentinel // 1. Var cur = sentinel for (index in 0 until m-1) {cur = cur.next!! Rear = cur} // 2. ReverseList (rear. Next!! , n-m + 1) return sentinel. Next} /** * reverse specified area * @param size */ fun reverseList(head: ListNode, size: Int): ListNode? { var cur: ListNode? = head var headP: ListNode? Val headTemp = head var count = 0 while (null! = cur.next cur.next = headP headP = cur = TMP count++} // connect to the NTH node headtemp.next = cur return headP } }Copy the code
Complexity analysis:
- Time complexity: Scan each node once, and the time complexity is O(n)O(n)O(n)
- Space complexity: Constant level variables are used and the space complexity is O(1)O(1)O(1)
234. Palindrome Linked ListĀ “Antithesis”
Determine if a linked list is palindromic.
Use the fast and slow pointer to find the middle node, reverse the last part of the list (based on reverse list II), compare whether the first and second parts of the list are the same, and finally reverse back to the original list.
class Solution { fun isPalindrome(head: ListNode?) : Boolean { if (null == head || null == head.next) { return true } // 1. Var fast = head var slow = head while (null! = fast && null ! = fast.next) { slow = slow!! .next fast = fast.next!! ReverseP = reverseList(slow!!) Var p = head var q: ListNode? = reverseP var isPalindrome = true while (null ! = p && null ! = q) { if (p.`val` == q.`val`) { p = p.next q = q.next } else { isPalindrome = false break } } // 4. Return isPalindrome} /** * private fun reverseList(head: ListNode): ListNode {// omitted, see the previous section... }}Copy the code
Complexity analysis:
- Time complexity: Scans each node twice, and the time complexity is O(n)O(n)O(n) O(n)
- Space complexity: Constant level variables are used and the space complexity is O(1)O(1)O(1)
Reverse Nodes in k-group Reverse Nodes in k-group
You are given a linked list, each k nodes in a group of flipped, please return to the flipped list.
4. Merge ordered lists
Merge ordered list questions appear in the interview frequency is high, among them, merge two ordered list is relatively simple, and its advanced version merge K ascending list factors to consider more comprehensive, the difficulty has also increased, come to try it.
21. Merge Two Sorted ListsĀ “Antithesis”
Merges two ascending lists into a new ascending list and returns. A new list is formed by concatenating all the nodes of a given two lists.
class Solution { fun mergeTwoLists(l1: ListNode? , l2: ListNode?) : ListNode? {if (null == L1) return l2 if (null == L2) return L1 // Sentinel node val sentinel = ListNode(-1) var rear = sentinel var p = L1 var q = l2 while (null ! = p && null ! = q) { if (p.`val` < q.`val`) { rear.next = p rear = p p = p.next } else { rear.next = q rear = q q = q.next } } rear.next = if (null ! = p) p else q return sentinel.next } }Copy the code
Complexity analysis:
- Time complexity: Scan each node once. The time complexity is O(m+ N)O(M + N)O(M + N)O(m+ N).
- Space complexity: Constant level variables are used and the space complexity is O(1)O(1)O(1)
23. Merge K Sorted Lists Merge K ascending ListsĀ “Antithesis”
You are given an array of linked lists, each of which has been sorted in ascending order. Please merge all lists into one ascending list and return the merged list.
Solution 1: Violence
Idea 1: Similar to merging two ordered lists, remove the smallest node from k lists in each round and insert it into the resulting list. Where, the time complexity of extracting the minimum node from the number of K is O(k)O(k)O(k).
Train of thought 2: This train of thought is similar to the last train of thought, with the same time complexity and space complexity page, namely: merge k linked lists and result linked lists in turn.
slightlyCopy the code
Complexity analysis:
- Time complexity: O(NK * K)O(NK * K)O(NK ā K)
- Space complexity: O(1)O(1)O(1)
Solution 2: Sorting
After storing all the nodes in an array, do a quick sort, and then output the array to a single linked list.
class Solution { fun mergeKLists(lists: Array<ListNode? >): ListNode? { if (lists.isNullOrEmpty()) { return null } // 1. Val array = ArrayList<ListNode>() for (list in lists) {var cur = list while (null! = cur) { array.add(cur) cur = cur.next } } // 2. SortWith (Comparator {node1, node2 -> node1. 'val' - node2. 'val'}) // 3. Val newHead = ListNode(-1) var rear = newHead for (node in array) {rear. Next = node rear = node} return newHead.next } }Copy the code
Complexity analysis:
- Time complexity: Merge node time O(NK)O(NK)O(NK)O, quick sort time O(NK ā LGNK)O(NK * LGNK)O(NK ā LGNK)O(NK * LGNK)O, output single linked list time O(NK)O(NK)O(NK)O, Total time complexity O(NK * LGNK)O(NK * LGNK)O(NK ā LGNK)
- Space complexity: Using array space O(nk)O(nk)O(nk)
Solution 3: merge
Split the k-list into two parts, then recursively process the two sets of lists, and finally merge them.
Class Solution {// Merge k ordered lists fun mergeKLists(Lists: Array<ListNode? >): ListNode? { if (lists.isNullOrEmpty()) { return null } return mergeKLists(lists, 0, lists.size - 1) } fun mergeKLists(lists: Array<ListNode? >, left: Int, right: Int): ListNode? {if (left == right) {return lists[left]} val mid = (left + right) ushr 1 return mergeTwoLists( MergeKLists (Lists, left, mid), mergeKLists(Lists, mid + 1, Right))} , l2: ListNode?) : ListNode? {// skip, see previous section... }}Copy the code
Complexity analysis:
- Time complexity: Time is mainly in the operation of merging linked lists. It can be seen from the recursive tree that the number of nodes at each level of the recursive tree is NKNKNK, and the height of the recursive tree is H = LGKH = LGK, so the total time complexity is O(NK ā LGK)O(NK * LGK)O(NK ā LGK)
- Space complexity: Using a recursive stack, the space complexity is O(LGK)O(LGK)O(LGK)
Solution 4: small top stack method
In solution 1, the time complexity of removing the smallest node from the number of K is O(k)O(k)O(k) O(k), and the minimum heap (priority queue) can be used to optimize to O(LGK)O(LGK)O(LGK). Where the in-heap node is always the head of the unprocessed portion of the K linked list.
Class Solution {// Merge k ordered lists fun mergeKLists(Lists: Array<ListNode? >): ListNode? {if (lists. IsNullOrEmpty ()) {return null} // Val queue = PriorityQueue<ListNode>(lists. Size) {node1, node2 -> node1.`val` - node2.`val` } // 1. For (list in lists) {if (null! = list) { queue.offer(list) } } val sentinel = ListNode(-1) var rear = sentinel // 2. While (queue.isnotempty ()) {val node = queue.poll()!! Rear. Next = node rear = node rear = node = node.next) { queue.offer(node.next) } } return sentinel.next } }Copy the code
Complexity analysis:
- Time complexity: For the binary heap of size K, the time to build the heap is O(k)O(k)O(k) O(k)O(k)O(k) O(k)O(k)O(k) O(k)O(k)O(K ā LGK)O(LGK)O(NK ā LGK)O(NK ā LGK)O(NK ā LGK)O(NK ā LGK)O(NK ā LGK)
- Space complexity: Binary heap space O(k)O(k)O(k)
5. Sort linked lists
Insertion Sort List Insertion Sort ListĀ |”Antithesis”
A: We have a Sort ListĀ “Antithesis”
6. Circular lists
Linked list intersection-loop problem can be classified as one kind of problem, which appears frequently in interview. In a previous article, we discussed separately: the algorithm of interview questions | chain table fellowship & cyclization problem”
Recommended reading
- Cryptography | is Base64 encryption algorithm?
- Java | show you understand the ServiceLoader principle and design idea
- Use annotations Java | this is a comprehensive strategy (including the Kotlin)
- Java | reflection: access type information at run time (including the Kotlin)
- Android | interview will ask Handler, are you sure you don’t look at it?
- Android | show you understand NativeAllocationRegistry principle and design idea
- Computer composition principle | Unicode utf-8 and what is the relationship?
- | why floating-point arithmetic of computer constitute principle is not accurate? (Ali written test)