链表总结
链表基础
如何实现一个单链表
#include "bits/stdc++.h"
using namespace std;
struct MyListNode
{
int data;
MyListNode *next;
MyListNode(int left = -1, MyListNode *right = nullptr) : data(left), next(right) {}
};
class MyLinkedList
{
public:
MyLinkedList() : m_size(0)
{
m_head = new MyListNode;
m_tail = new MyListNode;
m_head->next = m_tail; //初始化外部不可见节点,后续节点插入头尾之间
}
/**析构函数
~MyLinkedList()
{
MyListNode* p=m_head->next;
for(int i=0; i<m_size; i++)
{
MyListNode* p2=p;
p=p->next;
delete p2;
}
delete m_head;
delete m_tail;
}*/
MyListNode *reverse(MyListNode *head)
{
if (head == nullptr || head->next == nullptr)
{
return head;
}
MyListNode *next = head->next;
MyListNode *newHead = reverse(next);
next->next = head;
head->next = nullptr;
return newHead;
}
// api=> get
int get(int index)
{
if (index < 0 || index > m_size - 1) //入口参数合法性检验
return -1;
MyListNode *p = findpre(index);
return p->next->data;
}
MyListNode *getHead()
{
return findpre(1);
}
// api=>addAtHead
void addAtHead(int val)
{
insert(0, val); //三个插入接口统一成一般形式
}
// api=>addAtTail
void addAtTail(int val)
{
insert(m_size, val);
}
// api=>addAtIndex
void addAtIndex(int index, int val)
{
if (index > m_size) //入口参数调整取值0~链表长度
return;
if (index < 0)
index = 0;
insert(index, val);
}
// api=>deleteAtIndex
void deleteAtIndex(int index)
{
if (index < 0 || index > m_size - 1)
return; //入口参数合法性检验
MyListNode *p = findpre(index);
MyListNode *curNode = p->next;
p->next = p->next->next;
m_size--;
delete curNode;
}
// helper method
void printList()
{
for (int i = 0; i < m_size; i++)
{
cout << get(i) << " ";
}
}
private:
MyListNode *findpre(int index)
{
MyListNode *p = m_head;
while (index != 0)
{
p = p->next;
index--;
}
return p;
}
void insert(int index, int val)
{
MyListNode *preNode = findpre(index);
MyListNode *afterNode = preNode->next;
MyListNode *currNode = new MyListNode;
preNode->next = currNode;
currNode->next = afterNode;
currNode->data = val;
m_size++;
}
MyListNode *m_head;
MyListNode *m_tail;
int m_size;
};
int main()
{
MyLinkedList *linkedList = new MyLinkedList();
linkedList->addAtHead(1);
linkedList->addAtTail(3);
linkedList->addAtIndex(1, 2); //链表变为1-> 2-> 3
linkedList->printList();
cout << linkedList->get(1) << endl; //返回2
linkedList->deleteAtIndex(1); //现在链表是1-> 3
linkedList->printList();
cout << linkedList->get(1) << endl; //返回3
}
如何实现一个简单的双链表
struct MyListNode{
int val;
MyListNode *next;
MyListNode *prev;
MyListNode(int x=-1, MyListNode* left = nullptr,MyListNode* right =nullptr): val(x), prev(left), next(right) {}
};
class MyLinkedList {
private:
MyListNode *m_head;
//MyListNode *m_tail;
int m_size;
MyListNode *findNode(int index){
MyListNode *p = m_head->next;
while(index!=0){
p = p->next;
index--;
}
return p;
}
public:
/** Initialize your data structure here. */
MyLinkedList():m_size(0) {
m_head = new MyListNode;
//m_tail = new MyListNode;
m_head -> next = m_head->prev=m_head;
}
/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
int get(int index) {
if(index<0 || index>=m_size){
return -1;
}
MyListNode *p = findNode(index);
return p->val;
}
/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
void addAtHead(int val) {
MyListNode *cur = new MyListNode(val,m_head,m_head->next);
m_head->next->prev = cur;
m_head->next = cur;
m_size++;
}
/** Append a node of value val to the last element of the linked list. */
void addAtTail(int val) {
MyListNode *cur = new MyListNode(val,m_head->prev,m_head);
m_head->prev->next = cur;
m_head->prev = cur;
m_size +=1;
}
/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
void addAtIndex(int index, int val) {
if(index>m_size) return;
if(index<0) index = 0;
MyListNode *p = findNode(index);
MyListNode *pre = p->prev;
MyListNode *newNode = new MyListNode(val,pre,p);
pre->next = newNode;
p->prev = newNode;
m_size+=1;
}
/** Delete the index-th node in the linked list, if the index is valid. */
void deleteAtIndex(int index) {
if(index<0||index>=m_size){
return;
}
MyListNode *p = findNode(index);
MyListNode *pre = p->prev;
MyListNode *after = p->next;
pre->next = p->next;
after->prev = p->prev;
delete p;
m_size--;
}
};
/**
* 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);
*/
双指针法
1. 给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos
是 -1
,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
/**
* 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) {
bool flag = false;
ListNode *slow = head;
ListNode *fast = head;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
if(slow==fast){
return true;
}
}
return false;
}
};
2.给定一个链表,返回链表开始入环的第一个节点。
如果链表无环,则返回 null
。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos
是 -1
,则在该链表中没有环。
说明:不允许修改给定的链表。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getMeet(ListNode *head){
ListNode *slow = head;
ListNode *fast = head;
while(fast && fast->next){
slow = slow -> next;
fast = fast -> next ->next;
if(fast == slow){
return slow;
}
}
return NULL;
}
ListNode *detectCycle(ListNode *head) {
ListNode * meet = getMeet(head);
if(meet==nullptr) return NULL;
ListNode *cur = head;
while(meet&&cur){
if(cur==meet){
return cur;
}
cur=cur->next;
meet = meet->next;
}
return NULL;
}
};
3.相交链表
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
/**
* 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 * l1 = headA;
ListNode * l2 = headB;
while(l1!=l2){
l1 = (l1==nullptr)?headB:l1->next;
l2 = (l2==nullptr)?headA:l2->next;
}
return l1;
}
};
4. 删除倒数第N个节点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* fast = head;
ListNode* slow = head;
while(n-->0){
fast=fast->next;
}
if(fast==nullptr) return head->next;
while(fast->next){
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return head;
}
};
经典问题
1. 反转链表
206. Reverse Linked List (Easy)
头插法
/**
* 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) {
ListNode *newHead = new ListNode(-1);
while(head){
ListNode *next = head->next;
head->next = newHead->next;
newHead->next = head;
head = next;
}
return newHead->next;
}
};
递归
class Solution{
public:
ListNode *reverseList(ListNode* head){
if(!head||!head->next){
return head;
}
ListNode *nextNode = head->next;
ListNode *newHead = reverseList(head->next);
nextNode->next = head;
head->next = nullptr;
return newHead;
}
}
2. 奇偶链表
328. Odd Even Linked List (Medium)
Example:
Given 1->2->3->4->5->NULL,
return 1->3->5->2->4->NULL.
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(head==nullptr) return nullptr;
ListNode* odd=head,*even=head->next,*evenHead = even;
while(even && even->next){
odd->next = odd->next->next;
odd = odd->next;
even->next = even->next->next;
even = even->next;
}
odd->next = evenHead;
return head;
}
};
3. 回文链表
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
class Solution {
public:
bool isPalindrome(ListNode* head) {
if(head==nullptr || head->next == nullptr){
return true;
}
ListNode *slow =head,*fast = head->next;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
}
if(fast!=nullptr){
slow = slow->next;
}
cut(head,slow);
return isEqual(head,reverse(slow));
}
bool isEqual(ListNode* l1, ListNode* l2){
while(l1 && l2){
if(l1->val!=l2->val) return false;
l1 = l1->next;
l2 = l2->next;
}
return true;
}
ListNode* reverse(ListNode* head){
ListNode* newHead = new ListNode(-1);
while(head){
ListNode* next = head->next;
head->next = newHead->next;
newHead->next = head;
head = next;
}
return newHead->next;
}
void cut(ListNode* head, ListNode* cutNode){
while(head->next!=cutNode){
head = head->next;
}
head->next=nullptr;
}
};
4. 交换链表中的相邻节点
ListNode *swapPairs(ListNode *head)
{
ListNode *node = new ListNode(-1);
node->next = head;
ListNode *pre = node;
while (pre->next != nullptr && pre->next->next != nullptr)
{
ListNode *l1 = pre->next, *l2 = pre->next->next;
ListNode *next = l2->next;
l1->next = next;
l2->next = l1;
pre->next = l2;
pre = l1;
}
return node->next;
}
5. 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1==nullptr){
return l2;
}
if(l2==nullptr){
return l1;
}
if(l1->val<l2->val){
l1->next = mergeTwoLists(l1->next,l2);
return l1;
}else{
l2->next = mergeTwoLists(l1,l2->next);
return l2;
}
}
};
6.链表求和
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
class Solution {
public:
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2)
{
ListNode *newHead = new ListNode(-1);
ListNode *p = newHead;
int carry = 0;
while (l1 || l2 || carry != 0)
{
int x = l1 ? l1->val : 0;
int y = l2 ? l2->val : 0;
int sum = x + y + carry;
ListNode *node = new ListNode(sum % 10);
p->next = node;
p=p->next;
if(l1) l1=l1->next;
if(l2) l2=l2->next;
carry = sum / 10;
}
return newHead->next;
}
};
7. 删除重复节点
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head || !head->next) return head;
head->next = deleteDuplicates(head->next);
return head->val == head->next->val ? head->next : head;
}
};