Preface
Questions related to linked lists appear frequently in interviews. These questions are often the basis for solving other complex problems;
in this article, I will sort out the problems & solutions of linked list problems. If you can help, please like and pay attention. This is really important to me.
table of Contents
1 Overview
1.1 Definition of linked list
Linked list is a common basic data structure and a linear list. Different from the sequence table, each node in the linked list is not stored sequentially, but points to the next node through the node's pointer field.
1.2 Advantages and disadvantages of linked lists
1.3 Types of linked lists
Single linked list, double linked list, circular linked list, static linked list
2. Delete the linked list node
When deleting a linked list node, considering that the first node of the linked list (no predecessor node) may be deleted, for coding convenience, consider adding a sentinel node . Among them, in the problem of deleting the Nth node from the bottom of the linked list, it is a more important programming skill to use the speed pointer to find the Nth node from the bottom in a scan.
237. Delete Node in a Linked List [Problem Solution]
203. Remove Linked List Elements [Problem Solution]
不移除野指针
class Solution {
fun removeElements(head: ListNode?, `val`: Int): ListNode? {
// 哨兵节点
val sentinel = ListNode(-1)
sentinel.next = head
var pre = sentinel
var cur: ListNode? = sentinel
while (null != cur) {
if (`val` == cur.`val`) {
// 移除
pre.next = cur.next
} else {
pre = cur
}
cur = cur.next
}
return sentinel.next
}
}
移除野指针
class Solution {
fun removeElements(head: ListNode?, `val`: Int): ListNode? {
// 哨兵节点
val sentinel = ListNode(-1)
sentinel.next = head
var pre = sentinel
var cur: ListNode? = sentinel
while (null != cur) {
val removeNode = if (`val` == cur.`val`) {
// 移除
pre.next = cur.next
cur
} else {
pre = cur
null
}
cur = cur.next
if (null != removeNode) {
removeNode.next = null
}
}
return sentinel.next
}
}
19. Remove Nth Node From End of List Remove Nth Node From End of List [Problem Solution]
Given a linked list, delete the nth node from the bottom of the linked list, and return the head node of the linked 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
}
// 找到倒数第 k 个节点的前驱
while (null != fast!!.next) {
fast = fast.next
slow = slow!!.next
}
slow!!.next = slow.next!!.next
return sentinel.next
}
}
Complexity analysis:
Similarly, the middle node of 876. Middle of the Linked List [Problem Solution] also finds the middle node through the speed pointer:
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
}
}
86. Partition List [Problem Solution]
Delete all nodes in the linked list that are equal to the given value val.
Idea: Separating the linked list is nothing more than removing the nodes greater than or equal to val from the original linked list to the second linked list, and finally splicing the two linked 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
// 第二链表
var bigHead : ListNode? = null
var bigRear = bigHead
var cur = head
while (null != cur) {
if (cur.`val` >= x) {
// 大于等于:移除
pre.next = cur.next
if(null == bigHead){
bigHead = cur
bigRear = cur
}else{
bigRear!!.next = cur
bigRear = cur
}
} else {
pre = cur
}
if (null == cur.next) {
// 拼接
pre.next = bigHead
bigRear?.next = null
break
}
cur = cur.next
}
return sentinel.next
}
}
Complexity analysis:
328. Odd Even Linked List 【Problem Solution】
Idea: The odd-even linked list is nothing more than putting the odd node in one linked list first, placing the even node in another linked list, and finally connecting the even node to the end of the odd linked 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) {
// 偶节点
odd.next = even.next
odd = odd.next!!
// 奇节点
even.next = odd.next
even = even.next
}
odd.next = evenHead
// 头节点不动
return head
}
}
83. Remove Duplicates from Sorted List delete duplicate elements in the sorted list
82. Remove Duplicates from Sorted List II Remove Duplicates from Sorted List II
3. Reverse linked list
The frequency of reversal linked list questions in interviews is very, very high . I believe students who have had several interviews will agree with this point of view. Here, I have found 4 problems with inverted linked lists, extending from simple to difficult, come and try.
206. Reverse Linked List 【Problem Solution】
Reverse a singly 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
}
}
复制代码
Complexity analysis:
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
}
}
Complexity analysis:
92. Reverse Linked List II [Question Solution]
Given a linked list, rotate the linked list and move each node of the linked list k positions to the right, where k is a non-negative number.
class Solution {
fun reverseBetween(head: ListNode?, m: Int, n: Int): ListNode? {
if (null == head || null == head.next) {
return head
}
// 哨兵节点
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\. 反转指定区域
rear.next = reverseList(rear.next!!, n - m + 1)
return sentinel.next
}
/**
* 反转指定区域
* @param size 长度
*/
fun reverseList(head: ListNode, size: Int): ListNode? {
var cur: ListNode? = head
var headP: ListNode? = null
// 反转的起始点需要连接到第 n 个节点
val headTemp = head
var count = 0
while (null != cur && count < size) {
val tmp = cur.next
cur.next = headP
headP = cur
cur = tmp
count++
}
// 连接到第 n 个节点
headTemp.next = cur
return headP
}
}
Complexity analysis:
234. Palindrome Linked List 【Problem Solution】
Please determine whether a linked list is a palindrome linked list.
Idea: Use the fast and slow pointers to find the intermediate node, reverse the second half of the linked list (based on the reversed linked list II), compare whether the two linked lists are the same, and finally reverse to return to the original linked 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!!.next
}
// 2\. 反转后半段
val reverseP = reverseList(slow!!)
// 3\. 比较前后两段是否相同
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\. 恢复链表
reverseList(reverseP)
return isPalindrome
}
/**
* 反转链表
*/
private fun reverseList(head: ListNode): ListNode {
// 略,见上一节...
}
}
Complexity analysis:
25. K Reverse Nodes in k-Group
Give you a linked list, every k nodes are flipped, please return to the flipped linked list.
4. Combine ordered linked lists
Merging sorted linked list problems frequencies in the interview higher , which merge the two ordered list is relatively simple, and its advanced version merger of K ascending list of factors to be considered in a more comprehensive, the difficulty has also been enhanced, fast Come and try it.
21. Merge Two Sorted Lists [Problem Solution]
Combine two ascending linked lists into a new ascending linked list and return. The new linked list is composed by splicing all the nodes of the given two linked lists.
class Solution {
fun mergeTwoLists(l1: ListNode?, l2: ListNode?): ListNode? {
if (null == l1) return l2
if (null == l2) return l1
// 哨兵节点
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
}
}
Complexity analysis:
23. Merge k Sorted Lists [Problem Solution]
Give you an array of linked lists, each of which has been arranged in ascending order. Please merge all linked lists into an ascending linked list and return the merged linked list.
Solution 1: Violence
Idea 1: Similar to merging two ordered linked lists, the smallest node is taken from k linked lists in each round and inserted into the resulting linked list. Among them, the time complexity of extracting the smallest node from k numbers is O(k)O(k)O(k).
Idea 2: This idea is similar to the previous idea, the time complexity and space complexity page are the same, that is, k linked lists and result linked lists are merged in sequence.
略
Complexity analysis:
Solution 2: Sorting method
Idea: After storing all nodes in an array, perform a quick sort, and then output the array to a singly 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\. 快速排序
array.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
}
}
Complexity analysis:
Solution 3: merge method
Idea: Divide the k groups of linked lists into two parts, then process the two groups of linked lists recursively, and finally merge them.
class Solution {
// 合并 k 个有序链表
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)
)
}
// 合并两个有序链表
fun mergeTwoLists(l1: ListNode?, l2: ListNode?): ListNode? {
// 略,见上一节...
}
}
Complexity analysis:
Solution 4: Small top pile method
class Solution {
// 合并 k 个有序链表
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
// 存在后继节点,加入堆中
if (null != node.next) {
queue.offer(node.next)
}
}
return sentinel.next
}
}
Complexity analysis:
5. Sort Linked List
147. Insertion Sort List to insert and sort the linked list | 【Problem Solution】
148. Sort List [Problem Solution]
6. Circular Linked List
Linked list intersection & ring formation problems can be classified into a category of questions, which appear frequently in interviews; in a previous article, we discussed separately: "Algorithmic Intersection Questions | Linked List Intersection & Ring Formation Problems"
At last
The domestic Internet interview process is gradually moving closer to foreign countries. For large companies like Bytedance and BAT, shredding algorithmic questions has become a must. This is also a low-cost method for companies to interview and screen people. If you write an algorithm and pass it, either you are smart or you are diligent.
I hope everyone will pay attention and prepare well.
In addition, I put the most important and popular learning directions for Android that I have compiled during this time on my GitHub , which also contains self-learning programming routes in different directions, interview question collections/faces, and a series of technical articles.
The resources are continuously updated, and everyone is welcome to learn and discuss together.
Original address: https://juejin.cn/post/6882370280946302983