1.移除链表元素
就是续签prenode curnode 需要注意本地使用虚拟头节点逻辑更加简单
/**
* 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* removeElements(ListNode* head, int val) {
ListNode* dummyHead = new ListNode();
dummyHead->next=head;
ListNode* prenode= dummyHead;
ListNode* curnode= dummyHead->next;
while(curnode!=nullptr){
if(curnode->val==val){
ListNode* delenode=curnode;
prenode->next=curnode->next;
curnode=curnode->next;
delete delenode;
}else{
prenode=curnode;
curnode=curnode->next;
}
}
auto result = dummyHead->next;
delete dummyHead;
return result;
}
};
2.设计链表
class MyLinkedList {
struct LinkList{
LinkList * next;
int val;
LinkList():val(0),next(nullptr){}
LinkList(int value):val(value),next(nullptr){}
};
public:
MyLinkedList() {
dummy = new LinkList();
}
int get(int index) {
LinkList * cur = dummy->next;
int len =0;
while(cur!=nullptr){
len++;
cur=cur->next;
}
if(index>=len){
// 下标无效
return -1;
}
cur = dummy->next;
while(index--){
cur=cur->next;
}
return cur->val;
}
void addAtHead(int val) {
LinkList * head = new LinkList(val);
head->next = dummy->next;
dummy->next = head;
}
void addAtTail(int val) {
LinkList * tailp = new LinkList(val);
LinkList * cur = dummy;
while(cur->next!=nullptr){
cur = cur->next;
}
cur->next = tailp;
}
void addAtIndex(int index, int val) {
LinkList * cur = dummy->next;
int len =0;
while(cur!=nullptr){
len++;
cur=cur->next;
}
if(index>len){
return;
}
if(index==len){
addAtTail(val);
return;
}
LinkList * pre = dummy;
cur = dummy->next;
while(index--){
pre=cur;
cur=cur->next;
}
// 直接插入pre后面就可以了
LinkList * pnewnode = new LinkList(val);
pnewnode->next=pre->next;
pre->next=pnewnode;
}
void deleteAtIndex(int index) {
LinkList * cur = dummy->next;
int len =0;
while(cur!=nullptr){
len++;
cur=cur->next;
}
if(index>=len){
// 下标无效
return;
}
LinkList * pre = dummy;
cur = dummy->next;
while(index--){
pre=cur;
cur=cur->next;
}
pre->next = cur->next;
}
LinkList * dummy =nullptr;
};
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList* obj = new MyLinkedList();
* int param_1 = obj->get(index);
* obj->addAtHead(val);
* obj->addAtTail(val);
* obj->addAtIndex(index,val);
* obj->deleteAtIndex(index);
*/
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) {
ListNode* dummyHead = new ListNode();
dummyHead->next=nullptr;
ListNode* cur = head;
while(cur!=nullptr){
ListNode* nextnode = cur->next;
cur->next=dummyHead->next;
dummyHead->next=cur;
cur=nextnode;
}
ListNode* result = dummyHead->next;
delete dummyHead;
return result;
}
};
4.两两交换链表中的节点
使用虚拟头结点 找到pre 然后取 待交换的两个节点
ListNode* nextnode1=pre->next;
ListNode* nextnode2=pre->next->next;
另外注意 交换之后 pre更新位置不是两个节点的下一个节点 而是
pre=nextnode1;
/**
* 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) {
ListNode* dummyHead = new ListNode();
dummyHead->next=head;
ListNode* pre=dummyHead;
while(pre->next!=nullptr && pre->next->next!=nullptr){
ListNode* nextnode1=pre->next;
ListNode* nextnode2=pre->next->next;
ListNode* tempnode=nextnode2->next;
nextnode2->next=nextnode1;
nextnode1->next=tempnode;
pre->next=nextnode2;
pre=nextnode1;
}
ListNode* result=dummyHead->next;
delete dummyHead;
return result;
}
};
/**
* 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* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead = new ListNode();
dummyhead->next = head;
ListNode *slow=dummyhead;
ListNode *fast=dummyhead;
while(n--){
// 快指针先走n个节点
fast=fast->next;
if(fast==nullptr){
break;
}
}
if(fast==nullptr){
// 证明n已经大于节点个数 无意义
delete dummyhead;
return head;
}
while(fast->next!=nullptr){
slow=slow->next;
fast=fast->next;
}
ListNode *delenode=slow->next;
slow->next=delenode->next;
delete delenode;
ListNode * result = dummyhead->next;;
delete dummyhead;
return result;
}
};
6.链表相交
主要思路:
方法一:首先长的链表先移动差值个单位 然后 然后判断两个链表此时位置是否是同一个节点 不是的话一起一个单位 再次判断 还不是的话 再次移动 如此反复判断 直到其中一个链表移动到末尾即可。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int lenA =0;
ListNode *curA=headA;
while(curA){
lenA++;
curA=curA->next;
}
int lenB =0;
ListNode *curB=headB;
while(curB){
lenB++;
curB=curB->next;
}
// cur1指向更长的
ListNode * cur1=headA;
ListNode * cur2=headB;
int k = abs(lenA-lenB);
if(lenA<lenB){
swap(cur1,cur2);
}
while(k--){
cur1=cur1->next;
}
while(cur1!=nullptr){
if(cur1==cur2){
return cur1;
}else{
cur1=cur1->next;
cur2=cur2->next;
}
}
return nullptr;
}
};
方法二:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *curA= headA;
ListNode *curB= headB;
while(curA!=curB){
curA=curA==NULL?headB:curA->next;
curB=curB==NULL?headA:curB->next;
}
return curA;
}
};
7.环形链表II
注意
快慢指针都是从第一个节点出发
ListNode *slow=head;
ListNode *fast=head;
循环体内慢指针每次走一个节点 快指针每次走两个节点
slow = slow->next;
fast=fast->next->next;
如果快慢指针不相遇一直这么走 直到fastnullptr或者fast->nextnullptr结束 相遇的话 直接重新设置两个指针 一个从头节点出发 一个从相遇节点出发 每次比较 如果不是同一个节点 每次都走一个节点长度 直到相遇即可
ListNode *cur1=head;
ListNode *cur2=slow;
while(cur1!=cur2){
cur1=cur1->next;
cur2=cur2->next;
}
return cur1;
完整代码如下
/**
* 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 *slow=head;
ListNode *fast=head;
while(fast!=nullptr&&fast->next!=nullptr){
slow = slow->next;
fast=fast->next->next;
if(fast==slow){
ListNode *cur1=head;
ListNode *cur2=slow;
while(cur1!=cur2){
cur1=cur1->next;
cur2=cur2->next;
}
return cur1;
}
}
return nullptr;
}
};
额外常见链表题目补充
8.合并两个有序链表
思路:采用尾插法 循环结束后 最后看那个节点不为空 直接全部拼接在尾部即可。
/**
* 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* list1, ListNode* list2) {
ListNode * dummy = new ListNode();
ListNode * tail = dummy;
while(list1!=nullptr && list2!=nullptr){
if(list1->val>list2->val){
tail->next=list2;
tail = list2;
list2=list2->next;
}else{
tail->next=list1;
tail = list1;
list1=list1->next;
}
}
if(list1!=nullptr){
tail->next = list1;
}
if(list2!=nullptr){
tail->next = list2;
}
return dummy->next;
}
};
9.重排链表
主要思路是 先将链表平均分成两个链表(快指针要先走一步) 然后将第二个链表直接反转(头插法) 然后 将两个链表交叉连接(尾插法)
/**
* 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* reverse(ListNode* secondhead){
ListNode* dummy = new ListNode();
while(secondhead!=nullptr){
ListNode* next = secondhead->next;
secondhead->next = dummy->next;
dummy->next = secondhead;
secondhead=next;
}
return dummy->next;
}
void reorderList(ListNode* head) {
// 主要思路是 先将链表平均分成两个链表(快指针要先走一步) 然后将第二个链表直接反转(头插法) 然后 将两个链表交叉连接(尾插法)
ListNode* slow,* fast;
slow=head;
// 终端 将一个链表平均成两个链表 快指针最开始 一定要先走一步 题目中至少有一个节点 因此此处不用加以判断 head==null?
fast=head->next;
while(fast!=nullptr&&fast->next!=nullptr){
slow=slow->next;
fast=fast->next->next;
}
ListNode* secondhead = slow->next;
// 一定要注意断链
slow->next=nullptr;
ListNode* firsthead = head;
// 头插法将第二个链表反转
secondhead=reverse(secondhead);
ListNode* dummy = new ListNode();
// 尾插法
ListNode* tail = dummy;
int first=true;
while(firsthead!=nullptr && secondhead!=nullptr){
if(first){
tail->next = firsthead;
tail=firsthead;
firsthead=firsthead->next;
}else{
tail->next = secondhead;
tail=secondhead;
secondhead=secondhead->next;
}
first=!first;
}
if(firsthead!=nullptr){
tail->next = firsthead;
}
if(secondhead!=nullptr){
tail->next = secondhead;
}
head = dummy->next;
return;
}
};
10.奇偶链表
思路:维持两个链表 采用尾插法 注意拆成两个链表的时候 需要将尾部置为空
while(head!=nullptr){
...
if(i%2!=0){
// 尾插法
cur1->next=nullptr;
}else{
// 尾插法
cur2->next=nullptr;
}
...
}
完整代码
/**
* 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* oddEvenList(ListNode* head) {
ListNode* dummy1 = new ListNode();
ListNode* tail1=dummy1;
ListNode* dummy2 = new ListNode();
ListNode* tail2=dummy2;
int i=1;
while(head!=nullptr){
if(i%2!=0){
// 奇数
tail1->next = head;
tail1=head;
head=head->next;
tail1->next =nullptr;
}else{
// 偶数
tail2->next = head;
tail2=head;
head=head->next;
tail2->next =nullptr;
}
i++;
}
tail1->next = dummy2->next;
return dummy1->next;
}
};
11.排序奇升偶降链表
思路 先将一个链表按照奇偶拆成两个链表 注意每次才有尾插法拼接节点的时候 需要将尾部置为空(防止最后两个链表没有完全断链)
while(head!=nullptr){
...
if(i%2!=0){
// 尾插法
cur1->next=nullptr;
}else{
// 尾插法
cur2->next=nullptr;
}
...
}
完整代码
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @return ListNode类
*/
ListNode* reverse(ListNode* head){
ListNode* dummy=new ListNode(0);
while(head!=nullptr){
auto nextnode = head->next;
head->next= dummy->next;
dummy->next=head;
head=nextnode;
}
return dummy->next;
}
ListNode* sortLinkedList(ListNode* head) {
// write code here
ListNode* dummy1=new ListNode(0);
ListNode* dummy2=new ListNode(0);
ListNode* cur1 = dummy1;
ListNode* cur2 = dummy2;
int i =1;
while(head!=nullptr){
auto nextnode = head->next;
if(i%2!=0){
// 尾插法
cur1->next=head;
cur1=head;
cur1->next=nullptr;
}else{
// 尾插法
cur2->next=head;
cur2=head;
cur2->next=nullptr;
}
head=nextnode;
i++;
}
// 借助头结点反转链表
cur2 = reverse(dummy2->next);
cur1 = dummy1->next;
// 下面相当于合并两个有序链表
ListNode* dummy=new ListNode(0);
ListNode* tail=dummy;
while(cur2!=nullptr&&cur1!=nullptr){
if(cur2->val<cur1->val){
tail->next = cur2;
tail =cur2;
cur2=cur2->next;
}else{
tail->next = cur1;
tail =cur1;
cur1=cur1->next;
}
}
if(cur2!=nullptr){
tail->next = cur2;
}
if(cur1!=nullptr){
tail->next = cur1;
}
return dummy->next;
}
};
12.判断回文链表
/**
* 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 {
private:
ListNode* reverse(ListNode* head){
ListNode* dummy = new ListNode(0);
while(head!=nullptr){
auto nextnode = head->next;
head->next=dummy->next;
dummy->next=head;
head=nextnode;
}
return dummy->next;
}
public:
bool isPalindrome(ListNode* head)
{
// 先找到中间位置
ListNode* slow = head;
// 条件可知 至少一个节点 也就是此处不会越界
ListNode* fast = head->next;
while(fast!=nullptr && fast->next!=nullptr){
slow=slow->next;
fast=fast->next->next;
}
ListNode* second = slow->next;
// 链表的反转
second = reverse(second);
slow->next=nullptr;
ListNode* first = head;
while(first!=nullptr&&second!=nullptr){
if(first->val!=second->val){
return false;
}
first=first->next;
second=second->next;
}
return true;
}
};
11. K 个一组翻转链表
/**
* 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 {
ListNode* reverse(ListNode*start){
ListNode* dummy=new ListNode();
while(start!=nullptr){
auto nextnode = start->next;
start->next=dummy->next;
dummy->next=start;
start=nextnode;
}
return dummy->next;
}
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* pre,*start,*end,*nextnode;
ListNode* dummy=new ListNode();
dummy->next = head;
pre = dummy;
start = dummy->next;
end = nullptr;
nextnode = nullptr;
while(start!=nullptr){
int i;
end =start;
for(i=1;i<=k-1&&end!=nullptr;i++){
end=end->next;
}
if(end==nullptr){
// 长度已经不够 直接返回即可
return dummy->next;
}
nextnode = end->next;
//断链
end->next=nullptr;
pre->next = nullptr;
reverse(start);
pre->next=end;
start->next = nextnode;
pre = start;
start=nextnode;
}
return dummy->next;
}
};