✅ 高频链表面试题 相关例题:
1 2 3 输入:head = [3 ,2 ,0 ,-4 ], pos = 1  输出:true  解释:链表中有一个环,其尾部连接到第二个节点。 
 
1️⃣ 快慢指针 1 2 3 4 5 6 7 8 9 10 11 12 13 class  Solution  {public :    bool  hasCycle (ListNode* head)   {         ListNode *slow = head, *fast = head;         while  (fast && fast->next) {             slow = slow->next;             fast = fast->next->next;             if  (slow == fast)                 return  true ;         }         return  false ;     } }; 
 
给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始 )。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递 ,仅仅是为了标识链表的实际情况。
不允许修改  链表。
示例 1: 
1 2 3 输入:head = [3 ,2 ,0 ,-4 ], pos = 1  输出:返回索引为 1  的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。 
 
1️⃣ 快慢指针 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class  Solution  {public :    ListNode* detectCycle (ListNode* head)   {         ListNode *slow = head, *fast = head;         while  (fast && fast->next) {             slow = slow->next;             fast = fast->next->next;             if  (slow == fast) {                                  ListNode* node = head;                 while  (node != slow) {                     node = node->next;                     slow = slow->next;                 }                 return  slow;             }         }         return  nullptr ;     } }; 
 
1 2 3 4 5 6 7 8 9 10 11 class  Solution  {public :    ListNode* getIntersectionNode (ListNode* headA, ListNode* headB)   {         ListNode *p = headA, *q = headB;         while  (p != q) {             p = p ? p->next : headB;             q = q ? q->next : headA;         }         return  p;     } }; 
 
1️⃣ 迭代|三指针 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class  Solution  {public :    ListNode* reverseList (ListNode* head)   {         ListNode* pre = nullptr ;         ListNode* cur = head;         while  (cur) {             ListNode* nxt = cur->next;             cur->next = pre;             pre = cur;             cur = nxt;         }         return  pre;     } }; 
 
2️⃣ 递归 1 2 3 4 5 6 7 8 9 10 11 class  Solution  {public :    ListNode* reverseList (ListNode* head)   {         if  (!head || !head->next)             return  head;         ListNode* new_head = reverseList (head->next);         head->next->next = head;         head->next = nullptr ;            return  new_head;     } }; 
 
反转链表进阶:反转部分区间,找到区间 leftNode 与 rightNode,以及 leftNode 左节点 pre 与 rightNode 右节点 nxt,独立区间(断开连接)后反转再接回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class  Solution  {public :    ListNode* reverseList (ListNode* head)   {         ListNode* pre = nullptr ;         ListNode* cur = head;         while  (cur) {             ListNode* nxt = cur->next;             cur->next = pre;             pre = cur;             cur = nxt;         }         return  pre;     }     ListNode* reverseBetween (ListNode* head, int  left, int  right)   {         ListNode dummy (0 , head)  ;         ListNode* pre = &dummy;         int  t = left;         while  (--t) {             pre = pre->next;         }         ListNode* leftNode = pre->next;         ListNode* rightNode = leftNode;         t = right - left;         while  (t--) {             rightNode = rightNode->next;         }         ListNode* nxt = rightNode->next;                  pre->next = nullptr ;         rightNode->next = nullptr ;                  ListNode* node = reverseList (leftNode);                  pre->next = node;         leftNode->next = nxt;         return  dummy.next;     } }; 
 
1 2 3 输入:head = [1 ,2 ,3 ,4 ,5 ] 输出:[3 ,4 ,5 ] 解释:链表只有一个中间结点,值为 3  。 
 
1 2 3 输入:head = [1 ,2 ,3 ,4 ,5 ,6 ] 输出:[4 ,5 ,6 ] 解释:该链表有两个中间结点,值分别为 3  和 4  ,返回第二个结点。 
 
1️⃣ 快慢指针 1 2 3 4 5 6 7 8 9 10 11 class  Solution  {public :    ListNode* middleNode (ListNode* head)   {         ListNode *slow = head, *fast = head;         while  (fast && fast->next) {             slow = slow->next;             fast = fast->next->next;         }         return  slow;     } }; 
 
1️⃣ 回文链表判断 = 寻找中间节点 + 反转链表 前置题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class  Solution  {public :    ListNode* middleNode (ListNode* head)   {         ListNode *slow = head, *fast = head;         while  (fast && fast->next) {             slow = slow->next;             fast = fast->next->next;         }         return  slow;     }     ListNode* reverseList (ListNode* head)   {         ListNode *pre = nullptr , *cur = head;         while  (cur) {             ListNode* nxt = cur->next;             cur->next = pre;             pre = cur;             cur = nxt;         }         return  pre;     }     bool  isPalindrome (ListNode* head)   {         ListNode* mid = middleNode (head);         ListNode* head2 = reverseList (mid);         while  (head2) {             if  (head->val != head2->val) {                 return  false ;             }             head = head->next;             head2 = head2->next;         }         return  true ;     } }; 
 
1 2 输入:l1 = [1 ,2 ,4 ], l2 = [1 ,3 ,4 ] 输出:[1 ,1 ,2 ,3 ,4 ,4 ] 
 
1️⃣ 迭代(常用) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Solution  {public :    ListNode* mergeTwoLists (ListNode* list1, ListNode* list2)   {         ListNode dummy{};         ListNode* cur = &dummy;         while  (list1 && list2) {             if  (list1->val < list2->val) {                 cur->next = list1;                 list1 = list1->next;             } else  {                 cur->next = list2;                 list2 = list2->next;             }             cur = cur->next;         }         cur->next = list1 ? list1 : list2;         return  dummy.next;     } }; 
 
2️⃣ 递归 1 2 3 4 5 6 7 8 9 10 11 12 13 class  Solution  {public :    ListNode* mergeTwoLists (ListNode* list1, ListNode* list2)   {         if  (list1 == nullptr ) return  list2;          if  (list2 == nullptr ) return  list1;         if  (list1->val < list2->val) {             list1->next = mergeTwoLists (list1->next, list2);             return  list1;         }         list2->next = mergeTwoLists (list1, list2->next);         return  list2;     } }; 
 
1️⃣ 迭代 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class  Solution  {public :    ListNode* addTwoNumbers (ListNode* l1, ListNode* l2)   {         ListNode dummy;         ListNode* cur = &dummy;         int  carry = 0 ;         while  (l1 || l2 || carry) {             if  (l1) {                 carry += l1->val;                 l1 = l1->next;             }             if  (l2) {                 carry += l2->val;                 l2 = l2->next;             }             cur = cur->next = new  ListNode (carry % 10 );             carry /= 10 ;         }         return  dummy.next;     } }; 
 
2️⃣ 递归 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  Solution  {public :         ListNode* addTwoNumbers (ListNode* l1, ListNode* l2, int  carry = 0 )   {         if  (l1 == nullptr  && l2 == nullptr ) {              return  carry ? new  ListNode (carry) : nullptr ;          }         if  (l1 == nullptr ) {              swap (l1, l2);          }         int  sum = carry + l1->val + (l2 ? l2->val : 0 );          l1->val = sum % 10 ;          l1->next = addTwoNumbers (l1->next, (l2 ? l2->next : nullptr ), sum / 10 );          return  l1;     } }; 
 
1️⃣ 迭代|反转链表 + 两数相加 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class  Solution  {    ListNode* reverseList (ListNode* head)   {         ListNode* pre = nullptr , *cur = head;         while  (cur) {             ListNode* nxt = cur->next;             cur->next = pre;             pre = cur;             cur = nxt;         }         return  pre;     }     ListNode* addTwo (ListNode* l1, ListNode* l2)   {         ListNode dummy;          auto  cur = &dummy;         int  carry = 0 ;          while  (l1 || l2 || carry) {              if  (l1) carry += l1->val;              if  (l2) carry += l2->val;              cur = cur->next = new  ListNode (carry % 10 );              carry /= 10 ;              if  (l1) l1 = l1->next;              if  (l2) l2 = l2->next;          }         return  dummy.next;      } public :    ListNode* addTwoNumbers (ListNode* l1, ListNode* l2)   {         l1 = reverseList (l1);         l2 = reverseList (l2);         auto  l3 = addTwo (l1, l2);         return  reverseList (l3);     } }; 
 
2️⃣ 递归|反转链表 + 两数相加 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class  Solution  {    ListNode* reverseList (ListNode* head)   {         if  (head == nullptr  || head->next == nullptr ) {             return  head;         }         auto  new_head = reverseList (head->next);         head->next->next = head;          head->next = nullptr ;          return  new_head;     }          ListNode* addTwo (ListNode* l1, ListNode* l2, int  carry = 0 )   {         if  (l1 == nullptr  && l2 == nullptr ) {              return  carry ? new  ListNode (carry) : nullptr ;          }         if  (l1 == nullptr ) {              swap (l1, l2);          }         carry += l1->val + (l2 ? l2->val : 0 );          l1->val = carry % 10 ;          l1->next = addTwo (l1->next, (l2 ? l2->next : nullptr ), carry / 10 );          return  l1;     } public :    ListNode* addTwoNumbers (ListNode* l1, ListNode* l2)   {         l1 = reverseList (l1);         l2 = reverseList (l2);          auto  l3 = addTwo (l1, l2);         return  reverseList (l3);     } }; 
 
1️⃣ 快慢指针 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class  Solution  {public :    ListNode* removeNthFromEnd (ListNode* head, int  n)   {         ListNode dummy (0 , head)  ;         ListNode *fast = &dummy, *slow = &dummy;         while  (n--) {             fast = fast->next;         }         while  (fast->next) {             slow = slow->next;             fast = fast->next;         }         ListNode* d = slow->next;         slow->next = d->next;         delete  d;         return  dummy.next;     } }; 
 
1️⃣ 迭代|四指针 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class  Solution  {public :    ListNode* swapPairs (ListNode* head)   {         ListNode dummy (0 , head)  ;          ListNode* node0 = &dummy;         ListNode* node1 = head;         while  (node1 && node1->next) {              ListNode* node2 = node1->next;             ListNode* node3 = node2->next;             node0->next = node2;              node2->next = node1;              node1->next = node3;              node0 = node1;              node1 = node3;          }         return  dummy.next;      } }; 
 
2️⃣ 递归 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class  Solution  {public :    ListNode* swapPairs (ListNode* head)   {         if  (head == nullptr  || head->next == nullptr ) {             return  head;         }         ListNode* node1 = head;         ListNode* node2 = head->next;         ListNode* node3 = node2->next;         node1->next = swapPairs (node3);          node2->next = node1;          return  node2;      } }; 
 
1️⃣ 从「反转链表 · 迭代版」到「K 个一组翻转链表」 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class  Solution  {public :    ListNode* reverseKGroup (ListNode* head, int  k)   {         int  n = 0 ;         for  (ListNode* cur = head; cur; cur = cur->next) {             n++;         }         ListNode dummy (0 , head)  ;         ListNode* p0 = &dummy;         ListNode* prev = nullptr ;         ListNode* cur = head;         for  (; n >= k; n -= k) {             for  (int  i = 0 ; i < k; i++) {                 ListNode* nxt = cur->next;                 cur->next = prev;                 prev = cur;                 cur = nxt;             }             ListNode* last = p0->next;             p0->next = prev;             last->next = cur;             p0 = last;         }         return  dummy.next;     } }; 
 
2️⃣「206. 反转链表」+「92. 反转链表 II」 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 class  Solution  {public :         ListNode* reverseList (ListNode* head)   {         ListNode* pre = nullptr ;         ListNode* cur = head;         while  (cur) {             ListNode* nxt = cur->next;             cur->next = pre;             pre = cur;             cur = nxt;         }         return  pre;     }          ListNode* reverseBetween (ListNode* head, int  left, int  right)   {         ListNode dummy (0 , head)  ;         ListNode* pre = &dummy;         for  (int  i = 0 ; i < left - 1 ; i++) {             pre = pre->next;         }         ListNode* leftNode = pre->next;         ListNode* rightNode = leftNode;         for  (int  i = left; i < right; i++) {             rightNode = rightNode->next;         }         ListNode* nxt = rightNode->next;         rightNode->next = nullptr ;         reverseList (leftNode);         pre->next = rightNode;         leftNode->next = nxt;         return  dummy.next;     }     ListNode* reverseKGroup (ListNode* head, int  k)   {         int  n = 0 ;         ListNode* cur = head;         while  (cur) {             n++;             cur = cur->next;         }         if  (n < k) {             return  head;         }         ListNode* new_head = head;         int  times = n / k;         for  (int  i = 0 ; times--; i += k) {             ListNode* node = reverseBetween (new_head, i + 1 , i + k);             if  (i == 0 ) {                 new_head = node;             }         }         return  new_head;     } }; 
 
1 2 3 4 5 6 7 8 9 10 输入:lists = [[1 ,4 ,5 ],[1 ,3 ,4 ],[2 ,6 ]] 输出:[1 ,1 ,2 ,3 ,4 ,4 ,5 ,6 ] 解释:链表数组如下: [   1 ->4 ->5 ,   1 ->3 ->4 ,   2 ->6  ] 将它们合并到一个有序链表中得到。 1 ->1 ->2 ->3 ->4 ->4 ->5 ->6 
 
✅ 快手一面 ,面试官来一题简单题😊,最后还问了时间复杂度:假设 k 个链表,共 n 个节点,那时间复杂度为 $O(k·logk+n·logk)$ 即 $O(n·logk)$。
1️⃣ 最小堆 时间复杂度分析:假设 $k$ 个链表, 共 $n$ 个节点, 最小堆单次操作 $O(log k)$, 初始化堆需要 $O(k·logk)$, 那时间复杂度为 $O(k·logk + n·logk)$,即 $O(n·logk)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class  Solution  {public :    ListNode* mergeKLists (vector<ListNode*>& lists)   {         auto  cmp = [](const  ListNode* a, const  ListNode* b) {             return  a->val > b->val;         };         priority_queue<ListNode*, vector<ListNode*>, decltype (cmp)> pq;         for  (auto & head : lists) {             if  (head) {                 pq.push (head);             }         }         ListNode dummy{};         ListNode* head = &dummy;         while  (!pq.empty ()) {             ListNode* node = pq.top ();             pq.pop ();             head->next = node;             head = head->next;             if  (node->next)                 pq.push (node->next);         }         return  dummy.next;     } }; 
 
2️⃣ 分治法 前置题目:21. 合并两个有序链表 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class  Solution  {public :    ListNode* mergeTwoLists (ListNode* list1, ListNode* list2)   {         ListNode dummy{};         ListNode* cur = &dummy;         while  (list1 && list2) {             if  (list1->val < list2->val) {                 cur->next = list1;                 list1 = list1->next;             } else  {                 cur->next = list2;                 list2 = list2->next;             }             cur = cur->next;         }         cur->next = list1 ? list1 : list2;         return  dummy.next;     }     ListNode* mergeKLists (vector<ListNode*>& lists, int  l, int  r)   {         if  (l == r)             return  lists[l];         if  (l > r)             return  nullptr ;         int  m = (l + r) >> 1 ;         auto  left = mergeKLists (lists, l, m);         auto  right = mergeKLists (lists, m + 1 , r);         return  mergeTwoLists (left, right);     }     ListNode* mergeKLists (vector<ListNode*>& lists)   {         return  mergeKLists (lists, 0 , lists.size () - 1 );     } }; 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 struct  Node  {    int  key;     int  value;     Node* prev;     Node* next;     Node (int  k = 0 , int  v = 0 ) : key (k), value (v) {} }; class  LRUCache  {private :    Node* dummy;     int  capacity;     unordered_map<int , Node*> key_to_node;     void  remove (Node* node)   {         node->prev->next = node->next;         node->next->prev = node->prev;     }     void  push_front (Node* node)   {         node->next = dummy->next;         node->prev = dummy;         dummy->next->prev = node;         dummy->next = node;     }     Node* get_node (int  key)   {         if  (!key_to_node.count (key)) {             return  nullptr ;         }         Node* node = key_to_node[key];         remove (node);         push_front (node);         return  node;     } public :    LRUCache (int  capacity) : capacity (capacity), dummy (new  Node ()) {         dummy->next = dummy;         dummy->prev = dummy;     }     int  get (int  key)   {         Node* node = get_node (key);         return  node == nullptr  ? -1  : node->value;     }     void  put (int  key, int  value)   {         Node* node = get_node (key);         if  (node != nullptr ) {             node->value = value;             return ;         }         node = new  Node (key, value);         if  (key_to_node.size () == capacity) {             Node* last = dummy->prev;             remove (last);             key_to_node.erase (last->key);             delete  last;         }         key_to_node[key] = node;         push_front (node);     } }; 
 
1 2 输入:head = [[7 ,null],[13 ,0 ],[11 ,4 ],[10 ,2 ],[1 ,0 ]] 输出:[[7 ,null],[13 ,0 ],[11 ,4 ],[10 ,2 ],[1 ,0 ]] 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class  Solution  {public :    unordered_map<Node*, Node*> cacheNode;     Node* copyRandomList (Node* head)   {         if  (head == nullptr )             return  nullptr ;         if  (!cacheNode.count (head)) {             Node* newHead = new  Node (head->val);             cacheNode[head] = newHead;             newHead->next = copyRandomList (head->next);             newHead->random = copyRandomList (head->random);         }         return  cacheNode[head];     } }; 
 
给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字  。返回 已排序的链表  。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class  Solution  {public :    ListNode* deleteDuplicates (ListNode* head)   {         ListNode dummy (0 , head)  ;         auto  cur = &dummy;         while  (cur->next && cur->next->next) {             int  val = cur->next->val;             if  (cur->next->next->val == val) {                 while  (cur->next && cur->next->val == val) {                     cur->next = cur->next->next;                 }             } else  {                 cur = cur->next;             }         }         return  dummy.next;     } }; 
 
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
1 2 输入:head = [1 ,2 ,3 ,4 ,5 ], k = 2  输出:[4 ,5 ,1 ,2 ,3 ] 
 
思路:我们可以先将给定的链表连接成环,然后将指定位置断开。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class  Solution  {public :    ListNode* rotateRight (ListNode* head, int  k)   {         if  (k == 0  || !head || !head->next) {             return  head;         }         int  n = 1 ;         ListNode* iter = head;         while  (iter->next) {             iter = iter->next;             n++;         }         int  t = n - k % n;         if  (t == n)             return  head;         iter->next = head;          while  (t--) {             iter = iter->next;         }         ListNode* ret = iter->next;         iter->next = nullptr ;         return  ret;     } }; 
 
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于  x 的节点都出现在 大于或等于  x 的节点之前。
你应当 保留  两个分区中每个节点的初始相对位置。
1 2 输入:head = [1 ,4 ,3 ,2 ,5 ,2 ], x = 3  输出:[1 ,2 ,2 ,4 ,3 ,5 ] 
 
1️⃣ 模拟 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class  Solution  {public :    ListNode* partition (ListNode* head, int  x)   {         ListNode largeDummy (0 )  ;         ListNode* large = &largeDummy;         ListNode smallDummy (0 )  ;         ListNode* small = &smallDummy;         while  (head) {             if  (head->val < x) {                 small->next = head;                 small = small->next;             } else  {                 large->next = head;                 large = large->next;             }             head = head->next;         }         small->next = largeDummy.next;         large->next = nullptr ;         return  smallDummy.next;     } }; 
 
1️⃣ 归并排序(分治法)|链表的中间结点 + 合并两个有序链表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class  Solution  {public :         ListNode* middleNode (ListNode* head)   {         ListNode* pre = head;         ListNode* slow = head;         ListNode* fast = head;         while  (fast && fast->next) {             pre = slow;             slow = slow->next;             fast = fast->next->next;         }         pre->next = nullptr ;          return  slow;     }          ListNode* mergeTwoLists (ListNode* list1, ListNode* list2)   {         ListNode dummy;         ListNode* cur = &dummy;         while  (list1 && list2) {             if  (list1->val < list2->val) {                 cur->next = list1;                 list1 = list1->next;             } else  {                 cur->next = list2;                 list2 = list2->next;             }             cur = cur->next;         }         cur->next = list1 ? list1 : list2;         return  dummy.next;     }     ListNode* sortList (ListNode* head)   {         if  (!head || !head->next)             return  head;         ListNode* mid = middleNode (head);         ListNode* head1 = sortList (head);         ListNode* head2 = sortList (mid);         return  mergeTwoLists (head1, head2);     } };