Leetcode brushing notes (C++) - linked list
Sort out the ideas in the process of brushing the questions, and summarize and share them here.
github address: https://github.com/lvjian0706/Leetcode-solutions
The github project is just newly created, and the organized code and ideas will be uploaded one after another. The code is based on C++ and python. At the same time, the basic sorting algorithm will also be sorted and uploaded.
21. Merge two sorted linked lists
Merges two ascending lists into a new ascending list and returns. The new linked list is formed by splicing all the nodes of the given two linked lists.
Example:
Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
/*
合并有序链表:类似归并排序的思路
*/
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode node(0);
ListNode* new_head = &node;
while(l1 && l2){
if(l1->val <= l2->val){
new_head->next = l1;
l1 = l1->next;
}
else{
new_head->next = l2;
l2 = l2->next;
}
new_head = new_head->next;
}
while(l1){
new_head->next = l1;
l1 = l1->next;
new_head = new_head->next;
}
while(l2){
new_head->next = l2;
l2 = l2->next;
new_head = new_head->next;
}
return node.next;
}
};
82. Delete duplicate elements in sorted linked list II
Given a sorted linked list, delete all nodes containing duplicate numbers, and only keep the numbers that do not appear repeatedly in the original linked list.
Example 1:
Input: 1->2->3->3->4->4->5
Output: 1->2->5
Example 2:
Input: 1->1->1->2-> 3
output: 2->3
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/*
删除重复节点,只保留没有重复出现的数字:
1. 为了避免头节点重复需要删除,新建一个头节点指向原来的头节点,最后返回新建节点的next;
2. 定义last和fast节点用来遍历链表,并找出重复节点:
2.1 last和fast初始化为head节点,循环判断last和fast的next是否相等,如果相等,fast前进一位;
2.2 如果fast发生了变化,也就是last和fast不是同一个节点时,说明从last到fast之间是重复元素,new_head的next指向fast的下一个元素;
2.3 如果last和fast是同一个节点时,说明该元素不是重复元素,new_head前进到该元素;
2.4 last和fast前进一位,保证永远在new_head前面一位;
*/
ListNode* deleteDuplicates(ListNode* head) {
ListNode node(0);
ListNode* new_head = &node;
new_head->next = head;
ListNode* last = head;
ListNode* fast = head;
while(fast && fast->next){
while(fast->next && last->val == fast->next->val){
fast = fast->next;
}
if(last==fast){
new_head = last;
}
else{
new_head->next = fast->next;
}
last = new_head->next;
fast = new_head->next;
}
return node.next;
}
};
83. Delete duplicate elements in sorted list
Given a sorted linked list, remove all duplicate elements such that each element appears only once.
Example 1:
Input: 1->1->2
Output: 1->2
Example 2:
Input: 1->1->2->3->3
Output: 1->2->3
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/*
使用一个指针进行遍历:
1. 如果没有元素或者只有1个元素,直接返回;
2. 遍历链表,当下一个元素与当前元素相等时,指针的next指向next的next,用以删除重复的元素,直到下一个元素与当前元素不相等为止;
3. 指针指向下一个元素(与当前元素不相等的第一个元素);
*/
ListNode* deleteDuplicates(ListNode* head) {
if(!head || !head->next) return head;
ListNode* newHead = head;
while(newHead && newHead->next){
if(newHead->next->val==newHead->val){
newHead->next = newHead->next->next;
}
else{
newHead = newHead->next;
}
}
return head;
}
};
86. Separate linked list
Given a linked list and a certain value x, partition the linked list such that all nodes less than x precede nodes greater than or equal to x.
You should preserve the initial relative position of each node in the two partitions.
Example:
Input: head = 1->4->3->2->5->2, x = 3
Output: 1->2->2->4->3->5
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/*
分隔链表:
定义两个节点small_head和large_head,前者作为头节点存储小于x的节点,后者作为头节点存储大于等于x的节点,最后进行拼接;
注意结果链表的尾部应该为null;
*/
ListNode* partition(ListNode* head, int x) {
ListNode node1(0);
ListNode* small_head = &node1;
ListNode node2(0);
ListNode* large_head = &node2;
while(head){
if(head->val<x){
small_head->next = head;
small_head = small_head->next;
}
else{
large_head->next = head;
large_head = large_head->next;
}
head = head->next;
}
small_head->next = node2.next;
large_head->next = NULL;
return node1.next;
}
};
92. Reverse Linked List II
Reverses the linked list from position m to n. Use one sweep to complete the inversion.
Explanation:
1 ≤ m ≤ n ≤ length of linked list.
Example:
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/*
反转从m到n的链表:迭代法
使用first指针指向位置m,first_pre指向m-1,temp设为null,last指向位置m+1,last_next指向位置n+1;
使用fist,last以及temp将位置m到n进行反转,接着将first_pre指向反转后的子链表头,反转后的子链表尾指向n+1;
*/
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode* first = head;
ListNode node(0);
ListNode* first_pre = &node;
first_pre->next = head;
/*
将first指针指向位置m,first_pre指向位置m-1;
*/
for(int i=0; i<m-1; i++){
first = first->next;
first_pre = first_pre->next;
}
ListNode* last = first->next;
ListNode* temp = NULL;
/*
使用fist,last以及temp将位置m到n进行反转,此时temp指向位置m,first指向位置m+1;
*/
for(int i=m; i<n+1; i++){
first->next = temp;
temp = first;
first = last;
if(last) last = last->next;
}
first_pre->next->next = first;
first_pre->next = temp;
return node.next;
}
};
138. Copy Linked List with Random Pointers
Given a linked list, each node contains an additional random pointer, which can point to any node in the linked list or an empty node.
Requests to return a deep copy of this linked list.
We represent a linked list in input/output by a linked list of n nodes. Each node is represented by a [val, random_index]:
val: An integer representing Node.val.
random_index: The index of the node pointed to by the random pointer (ranging from 0 to n-1); null if it does not point to any node.
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/
class Solution {
public:
/*
复制带随机指针的链表:深拷贝
1. 循环遍历链表,一边遍历一边新建节点,将新节点赋值为与该节点一样的值,然后插入到该节点后边;
2. 再次循环遍历新链表,步长为2,一边遍历一边将后边的节点(1中新建的节点)的random赋值为与前边节点(原始节点)一致;
3. 将新链表拆分
*/
Node* copyRandomList(Node* head) {
Node* insert_head = head;
while(insert_head){
Node* temp_node = new Node(insert_head->val);
temp_node->next = insert_head->next;
insert_head->next = temp_node;
insert_head = insert_head->next->next;
}
Node* random_head = head;
while(random_head && random_head->next){
if(random_head->random) random_head->next->random = random_head->random->next;
else random_head->next->random = NULL;
random_head = random_head->next->next;
}
Node node(0);
Node* copy_head = &node;
Node* new_head = head;
while(new_head && new_head->next){
copy_head->next = new_head->next;
new_head->next = new_head->next->next;
new_head = new_head->next;
copy_head = copy_head->next;
}
copy_head->next = NULL;
return node.next;
}
};
141. Circular Linked List
Given a linked list, determine whether there is a cycle in the linked list.
To represent a cycle in a given list, we use the integer pos to denote the position in the list where the tail of the list joins (indexes start at 0). If pos is -1, there are no cycles in the list.
Example 1:
Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a ring in the linked list whose tail is connected to the second node.
Example 2:
Input: head = [1,2], pos = 0
Output: true
Explanation: There is a ring in the linked list whose tail is connected to the first node.
Example 3:
Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.
Advanced:
Can you solve this problem with O(1) (ie, constant) memory?
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/*
判断链表是否有环,使用快慢指针
快指针每次走两步,慢指针每次走一步,看是否可以碰面;主要关注边界情况
*/
bool hasCycle(ListNode *head) {
if(!head || !head->next) return false;
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if(fast==slow) return true;
}
return false;
}
};
142. Circular Linked List II
Given a linked list, return the first node where the linked list starts entering the ring. Returns null if the linked list is acyclic.
To represent a cycle in a given list, we use the integer pos to denote the position in the list where the tail of the list joins (indexes start at 0). If pos is -1, there are no cycles in the list.
Description: Modification of the given linked list is not allowed.
Example 1:
Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a ring in the linked list whose tail connects to the second node.
Example 2:
Input: head = [1,2], pos = 0
Output: tail connects to node index 0
Explanation: There is a ring in the linked list whose tail is connected to the first node.
Example 3:
Input: head = [1], pos = -1
Output: no cycle
Explanation: There is no cycle in the linked list.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/*
循环链表:
1. 首先判断是否是环,使用快慢指针,快指针每次走2步,慢指针每次走1步,看是否相遇,不相遇则返回null;
2. 如果相遇,设慢指针走了s,则快指针已经走了2s,假设从head到环的入口为a,环的长度为b,则s=nb,快指针比慢指针多走了nb;
3. 想要计算环的入口a,可以使用两个指针,一个在head处走a步,一个在相遇处走a步,此时,一个指针的位置为a,一个为a+nb,因为有环,所以a=a+nb;
4. 最终的相遇位置为环的入口;
*/
ListNode *detectCycle(ListNode *head) {
if(!head || !head->next) return NULL;
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if(fast==slow){
slow = head;
while(fast != slow){
fast = fast->next;
slow = slow->next;
}
return slow;
}
}
return NULL;
}
};
143. Rearrange Linked List
Given a singly linked list L: L0→L1→…→Ln-1→Ln,
after rearranging it becomes: L0→Ln→L1→Ln-1→L2→Ln-2→…
You can't just change the value inside the node, but need to actually swap the node.
Example 1:
Given linked list 1->2->3->4, rearrange to 1->4->2->3.
Example 2:
Given linked list 1->2->3->4->5 , rearranged as 1->5->2->4->3.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
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;
}
/*
重排列链表:将后半部分的链表倒序插入到前半部分链表中;
1. 使用快慢指针找到后半部分链表;
2. 反转后半部分链表;
3. 将右半部分链表插入到左半部分链表中;
*/
void reorderList(ListNode* head) {
if(!head || !head->next) return;
ListNode* fast = head->next;
ListNode* slow = head;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
}
ListNode* right_half = reverseList(slow->next);
slow->next = nullptr;
ListNode* new_head = head;
while(new_head && right_half){
ListNode* temp = right_half->next;
right_half->next = new_head->next;
new_head->next = right_half;
right_half = temp;
new_head = new_head->next->next;
}
/*
当右半部分链表还有一个元素没有插入进去时,单独处理;
*/
if(right_half){
right_half->next = new_head->next;
new_head->next = right_half;
}
}
};
148. Sorting Linked List
Sort a linked list in O(n log n) time complexity and constant level space complexity.
Example 1:
Input: 4->2->1->3
Output: 1->2->3->4
Example 2:
Input: -1->5->3->4->0
Output: -1 ->0->3->4->5
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/*
新建头节点,进行归并排序;
*/
ListNode* mergeSort(ListNode* left, ListNode* right){
ListNode node(0);
ListNode* new_head = &node;
while(left && right){
if(left->val<right->val){
new_head->next = left;
left = left->next;
}
else{
new_head->next = right;
right = right->next;
}
new_head = new_head->next;
}
while(left){
new_head->next = left;
left = left->next;
new_head = new_head->next;
}
while(right){
new_head->next = right;
right = right->next;
new_head = new_head->next;
}
return node.next;
}
/*
链表排序:
O(nlogn) 时间复杂度以及常数级空间复杂度,考虑归并排序
使用快慢指针找链表的中点,将链表分为前半部分和后半部分,递归的对前半部分以及后半部分进行排序,最后对两部分进行总的排序
其中,在分割时,需要将前半部分的尾指针next赋为null,将链表切断,否则会无限递归;后半部分的起始点则为slow->next;
*/
ListNode* sortList(ListNode* head) {
if(!head || !head->next) return head;
ListNode* fast = head->next;
ListNode* slow = head;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
}
ListNode* half = slow->next;
slow->next = NULL;
return mergeSort(sortList(head), sortList(half));
}
};
206. Reverse Linked List
Reverse a singly linked list.
Example:
Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL
Advanced:
You can reverse the linked list iteratively or recursively . Can you solve this problem two ways?
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/*
原地反转链表:方法1.递归
1. 递归结束条件:如果head为空或者链表只有1个节点,不需要反转,直接返回;
2. 当head->next之后的节点已经反转好了,将新的头结点保存为new_head;
3. 此时,头节点指向新链表的尾节点,需要将新链表的尾节点指向头节点(反转head和head->next),head->next->next = head;
4. 将头节点的next赋为空;
5. 返回新链表的头节点;
*/
ListNode* reverseList(ListNode* head) {
if(!head || !head->next) return head;
ListNode* new_head = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return new_head;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/*
原地反转链表:方法2.迭代
1. 递归结束条件:如果head为空或者链表只有1个节点,不需要反转,直接返回;
2. 使用三个指针,每次将当前指针指向前一个位置的指针,然后将三个指针同时向后移动一位;
*/
ListNode* reverseList(ListNode* head) {
ListNode* new_head = NULL;
while(head){
ListNode* head_next = head->next;
head->next = new_head;
new_head = head;
head = head_next;
}
return new_head;
}
};
234. Palindrome Linked List
Please determine whether a linked list is a palindromic linked list.
Example 1:
Input: 1->2
Output: false
Example 2:
Input: 1->2->2->1
Output: true
Advanced:
Can you use O(n) time complexity and O(1) space Complexity to solve this problem?
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
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 = NULL;
return new_head;
}
/*
判断是否是回文链表:
1. 使用快慢指针找到链表中点,将链表断开;
2. 将后半部分链表反转;
3. 比较两个链表的相同位置的值是否一致;
*/
bool isPalindrome(ListNode* head) {
if(!head || !head->next) return true;
ListNode* fast = head->next;
ListNode* slow = head;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
}
ListNode* right = reverseList(slow->next);
slow->next = NULL;
while(head && right){
if(head->val != right->val) return false;
head = head->next;
right = right->next;
}
return true;
}
};