1 ——Leetcode 876.链表的中间节点
/**
* 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* middleNode(ListNode* head) {
ListNode *fast=head,*slow=head;
while(fast&&fast->next){
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
};
2——Leetcode 138.复制带随机指针的链表|剑指 Offer 35. 复杂链表的复制
法一:哈希表
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/
#include <unordered_map>
class Solution {
public:
Node* copyRandomList(Node* head) {
unordered_map <Node*,Node*> map;
Node *cur=head;
while(cur!=NULL){
map.insert({cur,new Node(cur->val)});
cur=cur->next;
}
cur=head;
while(cur!=NULL){
map[cur]->next=map[cur->next];
map[cur]->random=map[cur->random];
cur=cur->next;
}
return map[head];
}
};
法二:拼接+拆分
考虑构建 原节点 1 -> 新节点 1 -> 原节点 2 -> 新节点 2 -> …… 的拼接链表,如此便可在访问原节点的 random 指向节点的同时找到新对应新节点的 random 指向节点。
注意点:需要单独处理原链表尾节点pre.next = null,否则报错。Next pointer of node with label 1 from the original list was modified.但是其实我们返回的是res,并不是原来的链表,所以不处理原链表尾节点按道理来说也没关系。
写了好久,后续再多练几遍
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head==NULL)return NULL;
Node *newhead=new Node (0);
Node*cur=head,*ncur=newhead;
while(cur){
ncur->next=new Node(cur->val);
ncur=ncur->next;
cur=cur->next;
}
newhead=newhead->next;
cur=head,ncur=newhead;
//两链表合并
while(cur){
//这里注意next后面会变,得先存
Node *next=ncur->next;
ncur->next=cur->next;
cur->next=ncur;
ncur=next;
//cur后面还加了一个
cur=cur->next->next;
}
cur=head;
ncur=head->next;
while(cur){
if(cur->random){
ncur->random=cur->random->next;
}
if(cur->next->next){
cur=cur->next->next;
ncur=cur->next;
}else{
break;
}
}
Node *res=head->next;
cur=head;
ncur=res;
while(true){
if(cur->next->next){
cur->next=cur->next->next;
ncur->next=ncur->next->next;
}else{
cur->next=NULL;
ncur->next=NULL;
break;
}
cur=cur->next;
ncur=ncur->next;
}
return res;
}
};
3——Leetcode 61.旋转链表
/**
* 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* rotateRight(ListNode* head, int k) {
if(head==NULL||k==0)return head;
int len=0;
ListNode *fast=head,*slow=head,*cur=head;
while(cur!=NULL){
len++;
cur=cur->next;
}
k=k%len;
if(k>0){
while(k--){
fast=fast->next;
}
while(fast->next!=NULL){
fast=fast->next;
slow=slow->next;
}
ListNode *newhead=slow->next;
slow->next=NULL;
fast->next=head;
return newhead;
}else{
return head;
}
}
};
4——剑指Offer 06 从头到尾打印链表
法一:
class Solution {
public:
vector<int> reversePrint(ListNode* head) {
vector<int>ans;
ListNode *cur=head;
while(cur){
ans.push_back(cur->val);
cur=cur->next;
}
reverse(ans.begin(),ans.end());
return ans;
}
};
法二:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<int> reversePrint(ListNode* head) {
vector<int>ans;
stack<int>st;
ListNode *cur=head;
while(cur){
st.push(cur->val);
cur=cur->next;
}
while(st.size()){
ans.push_back(st.top());
st.pop();
}
return ans;
}
};
法三:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<int>ans;
vector<int> reversePrint(ListNode* head) {
if(head==NULL)return ans;
ListNode *cur=head;
dfs(cur);
return ans;
}
void dfs(ListNode *cur){
if(cur->next!=NULL)reversePrint(cur->next);
ans.push_back(cur->val);
}
};
5 剑指 Offer 18. 删除链表的节点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteNode(ListNode* head, int val) {
//看到删除一定要申请一个保护节点,防止删除头结点时出错
ListNode *newNode=new ListNode(0);
newNode->next=head;
head=newNode;
ListNode *pre=head,*cur=head->next;
while(cur!=NULL){
if(cur->val==val){
pre->next=pre->next->next;
break;
}
pre=cur;
cur=cur->next;
}
return head->next;
}
};
6.剑指 Offer II 077. 链表排序
如果·要求复杂度O(nlogn),因此考虑使用快速排序或者归并排序,但是后来经过实践证明,使用快速排序总是AC超时,归并排序则可以正确AC。
分析一下原因,个人认为是与测试数据有关,因为快速排序不能保证算法复杂度一定是O(nlogn),当数据比较集中时,即使做随机选取key值,算法的复杂度也非常接近O(N^2),因此会出现超时,所以考虑使用归并排序。
法一:归并排序
/**
* 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* sortList(ListNode* head) {
if(head==NULL||head->next==NULL)return head;
ListNode *ans=mersort(head);
return ans;
}
ListNode *mersort(ListNode *node){
if(node==NULL||node->next==NULL)return node;
ListNode *fast=node,*slow=node,*pre=NULL;
while(fast!=NULL&&fast->next!=NULL){
fast=fast->next->next;
pre=slow;
slow=slow->next;
}
if(pre)pre->next=NULL;
ListNode*l1=mersort(node);
ListNode*l2=mersort(slow);
return merge(l1,l2);
}
ListNode *merge(ListNode *l1,ListNode *l2){
ListNode *cur1=l1,*cur2=l2,*cur=new ListNode(0),*head;
head=cur;
while(cur1!=NULL&&cur2!=NULL){
if(cur1->val<cur2->val){
cur->next=cur1;
cur1=cur1->next;
}else{
cur->next=cur2;
cur2=cur2->next;
}
cur=cur->next;
}
while(cur1!=NULL){
cur->next=cur1;
cur1=cur1->next;
cur=cur->next;
}
while(cur2!=NULL){
cur->next=cur2;
cur2=cur2->next;
cur=cur->next;
}
return head->next;
}
};
法二:快排
后序补上代码
7.剑指 Offer II 026. 重排链表
/**
* 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:
void reorderList(ListNode* head) {
ListNode *fast=head,*slow=head,*preslow=NULL;
while(fast!=NULL&&fast->next!=NULL){
fast=fast->next->next;
preslow=slow;
slow=slow->next;
}
if(fast){
preslow=slow;
slow=slow->next;
}
if(preslow)preslow->next=NULL;
ListNode *pre=NULL,*slowhead=NULL;
while(slow){
ListNode *next=slow->next;
if(next==NULL)slowhead=slow;
slow->next=pre;
pre=slow;
slow=next;
}
ListNode *cur=new ListNode(0),*ans=cur;
fast=head,slow=slowhead;
while(fast&&slow){
cur->next=fast;
fast=fast->next;
cur=cur->next;
cur->next=slow;
slow=slow->next;
cur=cur->next;
}
if(fast){
cur->next=fast;
}
head=ans->next;
}
};
8.剑指 Offer II 024. 反转链表
/**
* 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) {
ListNode *cur=head,*pre=NULL,*ans=NULL;
while(cur){
ListNode *next=cur->next;
if(next==NULL)ans=cur;
cur->next=pre;
pre=cur;
cur=next;
}
return ans;
}
};
9.剑指 Offer II 027. 回文链表
/**
* 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:
bool isPalindrome(ListNode* head) {
if(head==NULL||head->next==NULL)return true;
ListNode *fast=head,*slow=head,*preslow=NULL;
while(fast&&fast->next){
fast=fast->next->next;
preslow=slow;
slow=slow->next;
}
preslow->next=NULL;
if(fast&&fast->next==NULL){
slow=slow->next;
}
ListNode *pre=NULL,*cur=head;
fast=NULL;
while(cur){
ListNode *next=cur->next;
if(next==NULL)fast=cur;
cur->next=pre;
pre=cur;
cur=next;
}
while(fast&&slow){
if(fast->val!=slow->val)return false;
printf("fast=%d,slow=%d",fast->val,slow->val);
fast=fast->next;
slow=slow->next;
}
return fast==NULL&&slow==NULL;
}
};
10.剑指 Offer II 029. 排序的循环链表
三种可能:
①head=NULL;
②insertVal在链表环里属于中间值
③insertval最大/最小
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node() {}
Node(int _val) {
val = _val;
next = NULL;
}
Node(int _val, Node* _next) {
val = _val;
next = _next;
}
};
*/
class Solution {
public:
Node* insert(Node* head, int insertVal) {
Node *newNode =new Node(insertVal);
if(head==NULL){
head=newNode;
head->next=head;
return head;
}
Node *cur=head;
bool flag=false;
Node *maxNode=head;
while(cur){
if(cur->val<=insertVal&&cur->next->val>=insertVal){
newNode->next=cur->next;
cur->next=newNode;
break;
}
if(cur->val>=maxNode->val&&cur->val>cur->next->val)maxNode=cur;
if(flag&&cur==maxNode){
newNode->next=cur->next;
cur->next=newNode;
break;
}
cur=cur->next;
if(cur==head)flag=true;
}
return head;
}
};
11.剑指 Offer II 078. 合并排序链表
hard一下子就过了,就还挺突然的,挺像归并排序的,不多说了
/**
* 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* mergeKLists(vector<ListNode*>& lists) {
int len=lists.size();
if(len==0)return NULL;
if(len==1)return lists[0];
vector<ListNode*>newLists;
ListNode *mer;
int i=0;
for(i=0;i+1<len;i+=2){
mer=merge(lists[i],lists[i+1]);
newLists.push_back(mer);
}
if(i<len)newLists.push_back(lists[i]);
ListNode *ans=mergeKLists(newLists);
return ans;
}
ListNode *merge(ListNode *l1,ListNode *l2){
ListNode *head=new ListNode(0),*cur;
cur=head;
while(l1!=NULL&&l2!=NULL){
if(l1->val<l2->val){
cur->next=l1;
l1=l1->next;
}else{
cur->next=l2;
l2=l2->next;
}
cur=cur->next;
}
while(l1){
cur->next=l1;
l1=l1->next;
cur=cur->next;
}
while(l2){
cur->next=l2;
l2=l2->next;
cur=cur->next;
}
return head->next;
}
};
12.1290. 二进制链表转整数
class Solution {
public:
int getDecimalValue(ListNode* head) {
int ans=0;
ListNode *cur=head;
while(cur){
ans=ans*2+cur->val;
cur=cur->next;
}
return ans;
}
};
13.817. 链表组件
注意审题
/**
* 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:
int numComponents(ListNode* head, vector<int>& nums) {
unordered_set<int>G(nums.begin(),nums.end());
ListNode *cur=head;
int cnt=0;
while(cur){
if(G.count(cur->val)){
while(cur&&G.count(cur->val))cur=cur->next;
cnt++;
}else{
cur=cur->next;
}
}
return cnt;
}
};
14.86.分隔链表
一开始想拿类似快排交换指针写,发现快排会让链表初始相对位置改变
那就拿两个指针把小于的串在一起,大于等于的串在一起,最后进行拼接
注意大于的那串最后置空
/**
* 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* partition(ListNode* head, int x) {
ListNode *lhead=new ListNode(0),*ghead=new ListNode(0);
ListNode *lt=lhead,*gt=ghead;
ListNode *cur=head;
while(cur){
if(cur->val<x){
lt->next=cur;
lt=lt->next;
}else{
gt->next=cur;
gt=gt->next;
}
cur=cur->next;
}
gt->next=NULL;
lt->next=ghead->next;
return lhead->next;
}
};
15. 24. 两两交换链表中的节点
法一:递归
/**
* 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* swapPairs(ListNode* head) {
if(head==NULL||head->next==NULL)return head;
ListNode *newHead=head->next;
head->next=swapPairs(newHead->next);
newHead->next=head;
return newHead;
}
};
法二:迭代
/**
* 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* swapPairs(ListNode* head) {
if(head==NULL||head->next==NULL)return head;
ListNode *newNode=new ListNode(0),*cur;
newNode->next=head;
cur=newNode;
while(cur->next&&cur->next->next){
ListNode*left=cur->next;
ListNode *right=cur->next->next;
left->next=right->next;
right->next=left;
cur->next=right;
cur=cur->next->next;
}
return newNode->next;
}
};
16.剑指 Offer II 022. 链表中环的入口节点
就一数学题,注意fast==slow只能证明有环,要找到入环的第一个节点还得找到从起点和相交点开始走的下一次相交点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *fast=head;
ListNode *slow=head;
while(fast&&fast->next){
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
fast=head;
while(fast!=slow){
fast=fast->next;
slow=slow->next;
}
return slow;
}
}
return NULL;
}
};
17.147. 对链表进行插入排序
tail指针非常关键,指向最后一个好排序的节点
分成2类,大于tail->val和小于tail->val
/**
* 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* insertionSortList(ListNode* head) {
if(head==NULL||head->next==NULL)return head;
在头指针新设个指针方便改变第一个数
ListNode *newNode=new ListNode(0);
newNode->next=head;
head=newNode;
//第一个数可以不排
ListNode *cur=head->next->next,*tail=head->next;
while(cur){
if(cur->val>=tail->val){
tail=tail->next;
}else{
ListNode *pre=head;
while(pre->next->val<cur->val){
pre=pre->next;
}
tail->next=cur->next;
cur->next=pre->next;
pre->next=cur;
}
cur=tail->next;
}
return head->next;
}
};
18.1019. 链表中的下一个更大节点
单调栈,不太熟悉,这几天多刷刷
可以参考
https://blog.csdn.net/lucky52529/article/details/89155694
讲的挺好
/**
* 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:
vector<int> nextLargerNodes(ListNode* head) {
vector<int>res;
if(head==NULL)return res;
ListNode *cur=head;
vector<int>nums;
while(cur){
nums.push_back(cur->val);
cur=cur->next;
}
stack<int>st;
int len=nums.size();
res.resize(len);
//建一个递减栈
for(int i=0;i<len;i++){
if(st.empty()){
st.push(i);
}else{
while(st.size()&&nums[st.top()]<nums[i]){
res[st.top()]=nums[i];
st.pop();
}
st.push(i);
}
}
return res;
}
};