//快慢指针
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == NULL)
return head;
ListNode* pre = NULL, *cur = head, *tmp;
while(cur != NULL){
tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
};
//递归
class Solution {
public:
ListNode* reverse(ListNode* pre, ListNode* cur){
if(cur == NULL){
return pre;
}
ListNode* tmp = cur->next;
cur->next = pre;
// 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
// pre = cur;
// cur = temp;
return reverse(cur, tmp);
}
ListNode* reverseList(ListNode* head) {
if(head == NULL)
return head;
// 和双指针法初始化是一样的逻辑
// ListNode* cur = head;
// ListNode* pre = NULL;
return reverse(NULL, head);
}
};
设置虚拟头结点的作用:
移除了一个头结点,是不是发现,在单链表中移除头结点 和 移除其他节点的操作方式是不一样,其实在写代码的时候也会发现,需要单独写一段逻辑来处理移除头结点的情况。设置虚拟头结点后, 原链表的所有节点就都可以按照统一的方式进行移除了。
//快慢指针
//fast先走n+1步,然后slow开始同步走
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* fast = dummyHead, *slow = dummyHead;
for(int i = 0; i <= n ; i++)
fast = fast->next;
while(fast != NULL){
fast = fast->next;
slow = slow->next;
}
ListNode* del = slow->next;
slow->next = del->next;
delete del;
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
};
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* cur = dummyHead->next;
ListNode* pre = dummyHead;
while(cur != NULL){
if(cur->val == val){
ListNode* del = cur;
pre->next = cur->next;
cur = pre->next;
delete del;
}
else{
pre = cur;
cur = cur->next;
}
}
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
};
题解:https://leetcode-cn.com/problems/reorder-list/solution/dong-hua-yan-shi-kuai-man-zhi-zhen-143-z-4kmk/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
};
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* slow = head, *fast = head;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
if(fast == slow) return true;
}
return false;
}
};
设置快慢指针,慢指针每走一步,快指针走两步,如果存在环,则快指针肯定会先走进环,慢指针后进入环。
又因为快指针走的比慢指针快,故二者终会相邻,然后再慢指针走一步,快指针走两步,二者就会相遇。
1.找到链表中间结点(若结点个数为偶数个,则返回中间第一个结点)
2.反转中间结点后面的链表
3.将链表前半部分和反转后的后半部分进行合并
题解:https://leetcode-cn.com/problems/reorder-list/solution/dong-hua-yan-shi-kuai-man-zhi-zhen-143-z-4kmk/
class Solution {
public:
ListNode* findMin(ListNode* head){
ListNode* slow = head, *fast = head;
while(fast->next != NULL && fast->next->next != NULL){
fast = fast->next->next;
slow = slow->next;
}
return slow; //为偶数个的话,返回中间两个结点的前面一个
}
ListNode* reverseList(ListNode* head){
ListNode* pre = NULL, *cur = head, *tmp;
while(cur != NULL){
tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
void mergeList(ListNode* head1, ListNode* head2){
ListNode* next1 = NULL, *next2 = NULL;
while(head1 != NULL && head2 != NULL){
next1 = head1->next;
next2 = head2->next;
head1->next = head2;
head1 = next1;
head2->next = head1;
head2 = next2;
}
}
void reorderList(ListNode* head) {
if(head == NULL)
return;
ListNode* mid = findMin(head);
//中间结点后面的部分进行反转
ListNode* head2 = mid->next;
mid->next = NULL;
head2 = reverseList(head2);
ListNode* head1 = head;
mergeList(head1, head2);
}
};
- 先求链表长度,若k大于链表长度,则用k对长度取余。
- 求倒数第k个结点的前一个结点
- 让倒数第k个结点成为头结点
题解:https://leetcode-cn.com/problems/rotate-list/solution/dong-hua-yan-shi-kuai-man-zhi-zhen-61-xu-7bp0/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if(k == 0 || head == NULL)
return head;
ListNode* tmp = head;
int cnt = 0;
while(tmp != NULL){
cnt++;
tmp = tmp->next;
}
k = k % cnt;
ListNode* slow = head, *fast = head, *fastPre = head;
for(int i = 0; i < k+1; i++)
fast = fast->next;
for(int i = 0; i < k; i++)
fastPre = fastPre->next;
while(fast != NULL){
fast = fast->next;
slow = slow->next;
fastPre = fastPre->next;
}
fastPre->next = head;
head = slow->next;
slow->next = NULL;
return head;
}
};
//归并排序
//空复O(logn) 时复O(nlogn)
class Solution {
public:
ListNode* sortList(ListNode* head) {
if(head == NULL || head->next == NULL) return head;
ListNode* slow = head, *fast = head;
while(fast->next != NULL && fast->next->next != NULL){
slow = slow->next;
fast = fast->next->next;
}
ListNode* rightHead = slow->next;
slow->next = NULL; //cut
ListNode* left = sortList(head);
ListNode* right = sortList(rightHead);
return Merge(left, right);
}
ListNode* Merge(ListNode* h1, ListNode* h2){
ListNode* dummyHead = new ListNode(0);
ListNode* p = dummyHead;
while(h1 != NULL && h2 != NULL){
if(h1->val < h2->val){
p->next = h1;
h1 = h1->next;
}
else{
p->next = h2;
h2 = h2->next;
}
p = p->next;
}
if(h1)
p->next = h1;
else
p->next = h2;
return dummyHead->next;
}
};
前缀和+hashmap
删除结点就要用到dummyhead
class Solution {
public:
ListNode* removeZeroSumSublists(ListNode* head) {
ListNode* cur = head;
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
int preSum = 0;
unordered_map<int, ListNode*> mp;
mp[0] = dummyHead;
while(cur != NULL){
preSum += cur->val;
if(mp.find(preSum) != mp.end()){
ListNode* tmp = mp[preSum]->next;
mp[preSum]->next = cur->next;
int tmpSum = preSum;
while(tmp != cur){
tmpSum += tmp->val;
mp.erase(tmpSum);
tmp = tmp->next;
}
}else{
mp[preSum] = cur;
}
cur = cur->next;
}
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
};
整个链表分为已反转区、待反转区和未反转区
指针分别为 pre, start end,next;
class Solution {
public:
ListNode* reverseList(ListNode* head){
ListNode* pre = NULL, *cur = head;
while(cur != NULL){
ListNode* tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
ListNode* reverseKGroup(ListNode* head, int k) {
if(head->next == NULL || k == 1)
return head;
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* pre = dummyHead;
ListNode* end = head, *start = head;
while(start != NULL){
int tmp = k - 1;
while(tmp && end != NULL){
tmp--;
end = end->next;
}
if(end == NULL)
break;
ListNode* next = end->next;
end->next = NULL;
pre->next = reverseList(start);
pre = start;
start->next = next;
start = next;
end = start;
}
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
};
哈希表
- 首先构造原链表节点宇新节点之间的哈希映射关系。
- 构造每个节点的next和random。
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head == NULL) return head;
unordered_map<Node* , Node*> mp;
Node* cur = head;
//1. 首先构造原链表节点宇新节点之间的哈希映射关系。
while(cur){
mp[cur] = new Node(cur->val);
cur = cur->next;
}
//2. 构造每个节点的next和random。
cur = head;
while(cur){
mp[cur]->next = mp[cur->next];
mp[cur]->random = mp[cur->random];
cur = cur->next;
}
return mp[head];
}
};