文章目录
- 一. 合并两个有序链表
- 题目解析
- 算法原理
- 代码编写
- 二. 相交链表问题
- 题目解析
- 算法原理
- 代码编写
- 三. 环形链表问题
- 1. 判断是否有环
- 2. 计算环的长度
- 3. 找到环的入口点
- 四. 反转链表
- 方法一:边迭代、边逆置
- 方法二:头插
- 五. 判断链表是否回文
- 题目解析
- 算法原理
- 代码编写
- 六、删除排序链表中的重复元素问题
- 1. 删除排序链表中的重复元素I
- 2. 删除排序链表中的重复元素II
- 七. 随机链表的复制
- 题目解析
- 算法原理
- 代码编写
一. 合并两个有序链表
题目解析
算法原理
同时遍历两个链表,取 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* mergeTwoLists(ListNode* list1, ListNode* list2) {// 1、预处理(创建哨兵位头节点)ListNode* head, *tail;head = tail = new ListNode();// 2、遍历并合并两个两个链表while(list1 != nullptr && list2 != nullptr){if(list1->val < list2->val) {tail->next = list1;list1 = list1->next;}else{tail->next = list2;list2 = list2->next;}tail = tail->next;}// 3、处理未遍历完的那个链表if(list1 != nullptr) tail->next = list1;else tail->next = list2;// 4、返回最终结果ListNode* ans = head->next;delete head;return ans;}
};
二. 相交链表问题
题目解析
算法原理
代码编写
/*** 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) {// 1、判断两个链表是否相交 && 计算两个链表的长度int lenA = 1, lenB = 1; //链表长度ListNode *ltA = headA, *ltB = headB; //链表最后一个节点while(ltA && ltA->next) ltA = ltA->next, ++lenA; //寻找A最后一个节点 和 统计链表长度while(ltB && ltB->next) ltB = ltB->next, ++lenB; //寻找B最后一个节点 和 统计链表长度if(ltA != ltB) return nullptr; //判断是否相交// 2、寻找初始相交节点int gap = abs(lenA - lenB); //链表长度差值ListNode *longList = headA, *shortList = headB; //创建长、短链表指针if(lenA < lenB) std::swap(longList, shortList);//确认长、短链表指针while(gap--) longList = longList->next; //长链表先走 gap 步while(longList != shortList) //两个链表同步走{longList = longList->next;shortList = shortList->next;}// 3、返回值return longList; }
};
/*
- 时间复杂度:O(m+n)
- 空间复杂度:O(1)
*/
三. 环形链表问题
1. 判断是否有环
解题思路
代码编写
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/typedef struct ListNode ListNode;bool hasCycle(struct ListNode *head)
{//空链接情况的处理if(!head){return false;}ListNode* fast=head;ListNode* slow=head;//fast一次走两步,为了防止空指针的访问要两个条件的判断while(fast&&fast->next){slow=slow->next;fast=fast->next->next;if(slow==fast){return true;}}return false;
}
2. 计算环的长度
算法原理
3. 找到环的入口点
算法原理
代码编写
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*///先记录fast和slow相遇时的节点//在定义一个节点从头开始//二者每次走一步//最后相遇时的节点就是入环节点typedef struct ListNode ListNode;struct ListNode *detectCycle(struct ListNode *head)
{ ListNode* slow=head;ListNode* fast=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;if(slow==fast){ListNode* meet=slow;while(1){if(head==meet){return head;}head=head->next;meet=meet->next;}}}return NULL;
}
四. 反转链表
方法一:边迭代、边逆置
算法原理
代码编写
// 方法一:边迭代、边逆置
class Solution
{
public:ListNode* reverseList(ListNode* head) {if(!head) return nullptr;// 1、初始化ListNode* n1 = nullptr;ListNode* n2 = head;ListNode* n3 = head->next;// 2、逆置while(n2){n2->next = n1;n1 = n2;n2 = n3;if(n3) n3 = n3->next;}// 3、返回值return n1;}
};
方法二:头插
算法原理
代码编写
class Solution
{
public:ListNode* reverseList(ListNode* head) {// 1、初始化ListNode* cur = head, *newHead = nullptr;// 2、头插while(cur){ListNode* next = cur->next;cur->next = newHead;newHead = cur;cur = next;}// 3、返回值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
{
private:ListNode* ReverseList(ListNode* head){if(!head) return nullptr;ListNode* n1 = nullptr, *n2 = head, *n3 = head->next;while(n2){n2->next = n1;n1 = n2;n2 = n3;if(n3) n3 = n3->next;}return n1;}public:bool isPalindrome(ListNode* head) {// 1、找到中间节点ListNode* fast, *slow;fast = slow = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}// 2、逆置后半段链表ListNode* half = ReverseList(slow);// 3、比较前后部分链表while(head && half){if(head->val != half->val) return false;head = head->next;half = half->next;}// 4、返回值return true;}
};
六、删除排序链表中的重复元素问题
1. 删除排序链表中的重复元素I
算法原理
代码编写
/*** 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* deleteDuplicates(ListNode* head) {// 0、特殊情况处理(保证链表至少有两个节点才做处理)if(head == nullptr || head->next == nullptr) return head;// 1、初始化ListNode* newHead, *tail; newHead = tail = head;//新链表第一个节点为 headhead = head->next; //旧链表从第二个节点开始遍历 tail->next = nullptr; //设置新链表中第一个节点的 next 为空 // 2、删除重复元素while(head){ListNode* cur = head;head = head->next;if(cur->val != tail->val){tail->next = cur;tail = cur;tail->next = nullptr;}}// 3、返回值return newHead;}
};
2. 删除排序链表中的重复元素II
算法原理
代码编写
/*** 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* deleteDuplicates(ListNode* head) {// 0、特殊情况处理(保证链表至少有两个节点才做处理)if(head == nullptr || head->next == nullptr) return head;// 1、初始化ListNode* newHead, *tail; newHead = tail = head;//新链表第一个节点为 headhead = head->next; //旧链表从第二个节点开始遍历 tail->next = nullptr; //设置新链表中第一个节点的 next 为空 // 2、删除重复元素while(head){ListNode* cur = head;head = head->next;if(cur->val != tail->val){tail->next = cur;tail = cur;tail->next = nullptr;}}// 3、返回值return newHead;}
};
七. 随机链表的复制
题目解析
算法原理
代码编写
/*
// 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:Node* copyRandomList(Node* head) {// 1、拷贝节点到原节点的后面Node* cur = head;while(cur){// 初始化Node* copy = new Node(cur->val);Node* next = cur->next;// 链接cur->next = copy;copy->next = next;// 更新curcur = next;}// 2、处理拷贝节点的 random 指针cur = head;while(cur){Node* copy = cur->next;if(cur->random) copy->random = cur->random->next;// 继续迭代原链表的下一个节点cur = cur->next->next;}// 3、拆解链表Node* newHead, *tail; //创造一个哨兵位头节点newHead = tail = new Node(0);cur = head;while(cur){// 初始化Node* copy = cur->next;Node* next = cur->next->next;// 尾插拷贝节点到新链表中tail->next = copy;tail = copy;tail->next = nullptr;// 处理原链表节点cur->next = next;cur = next;}// 4、返回值return newHead->next;}
};