链表
- 2.链表
-
- 2.4合并两个有序链表
- 2.5链表分割
- 2.6链表的回⽂结构
- 2.7相交链表
- 2.8环形链表I
- [2.9 环形链表II](#2.9 环形链表II)
- 2.10随机链表的复制
2.链表
2.4合并两个有序链表
思路
c
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
//处理链表为空的情况
if (list1 == NULL)
return list2;
if (list2 == NULL)
return list1;
//方一代码:创建新的空链表
ListNode* newhead = NULL, * newtail = NULL;
//list1,list2分别指向两个链表的表头
//newhead = newtail = (ListNode*)malloc(sizeof(ListNode));
while (list1 && list2)//只要有一个条件不满足就跳出循环
{
if (list1->val < list2->val)
{
//谁小谁尾插
if (newhead == NULL)
{
newhead = newtail = list1;
}
else
{
newtail->next = list1;
newhead = newtail->next;
}
list1 = list1->next;
}
else
{
//l2尾插
if (newhead == NULL)
{
newhead = newhead = list2;
}
else
{
newtail->next = list2;
newtail = newtail->next;
}
list2 = list2->next;
}
}
//跳出循环只有两种情况,list1为空或list2为空
if (list1)
{
newtail->next = list1;
}
if (list2)
{
newtail->next = list2;
}
return newhead;
}
c
//方二代码:创建一个非空链表
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//申请一个动态的空间
//此时初始了一个头结点,是个默认的值,最后删掉
ListNode* newhead, * newtail;
newhead = newtail = (ListNode*)malloc(sizeof(ListNode));
while (list1 && list2)
{
//不用判断链表是否为空,直接拿过来尾插
if (list1->val < list2->val)
{
newtail->next = list1;
list1 = list1->next;
}
else
{
newtail->next = list2;
list2 = list2->next;
}
newtail = newtail->next;
}
if (list1)
{
newtail->next = list1;
}
else
{
newtail->next = list2;
}
ListNode* ret = newhead->next;
free(newhead);
newhead = NUll;
return ret;
}
2.5链表分割
思路
c
单链表算法题----链表分割
牛客是c++写的
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
// write code here
if (pHead == NULL)
return NULL;
//创建两个非空链表,小链表和大
struct ListNode* lessHead, * lessTail, * greaterHead, * greaterTail;
//创建链表表头
//注意:我动态开辟空间后 lesshead链表和greathead链表头就有一个默认结点啦
lessHead = lessTail = (struct ListNode*)malloc(sizeof(struct ListNode));
greaterHead = greaterTail = (struct ListNode*)malloc(sizeof(struct ListNode));
//遍历原链表,找小于x的和其它节点尾插导大小链表中
struct ListNode* cur = pHead;
while (cur)
{
//小于x的尾插到lessTail
if (cur->val < x)
{
lessTail->next = cur;
lessTail = lessTail->next;
}
//大于等于x的尾插到greaterTail
else
{
greaterTail->next = cur;
greaterTail = greaterTail->next;
}
cur = cur->next;
}
//链接两个链表,小尾结点指向大的下一个结点
lessTail->next = greaterHead->next;
greaterTail->next = NULL;
//获取表头
pHead = lessHead->next;
free(lessHead);
free(greaterHead);
return pHead;
}
};
2.6链表的回⽂结构
思路
c
单链表算法题----链表的回⽂结构
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code here
if (A == NULL || A->next == NULL)
return true;
ListNode* slow, * fast, * prev, * cur, * nxt;
slow = fast = A;
//1.找到中间节点
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
//此时slow为中间结点
//后半部分逆置(反转链表)
prev = NULL;
cur = slow;
while (cur)
{
nxt = cur->next;
cur->next = prev;
prev = cur;
cur = nxt;
}
//逐点比对
while (A && prev)
//此时prev为最后一个结点
{
if (A->val != prev->val)
return false;
A = A->next;
prev = prev->next;
}
return true;
}
};
2.7相交链表
思路
c
单链表算法题----相交链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {
ListNode* p1 = headA;
ListNode* p2 = headB;
int sizeA, sizeB;
sizeA = sizeB = 0;
while (p1) {
sizeA++;
p1 = p1->next;
}
while (p2) {
sizeB++;
p2 = p2->next;
}
//求绝对值
int gap = abs(sizeA - sizeB);
//让长链表先走gap步
ListNode* longlist = headA;
ListNode* shortlist = headB;
if (sizeA < sizeB)
{
longlist = headB;
shortlist = headA;
}
while (gap--)
{
longlist = longlist->next;
}
//此时,longlist和shortlist在同一起跑线
//两种情况 相交,不相交
while (longlist && shortlist)
{
if (longlist == shortlist)
{
//链表相交
return shortlist;
}
//继续往后走
longlist = longlist->next;
shortlist = shortlist->next;
}
//都走到为空了,链表不相交
return NULL;
}
2.8环形链表I
思路证明见下篇
c
单链表算法题----环形链表I
//判断是否带环
//判断是否相遇,环形链表2下个题是找相遇点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
//走两步
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode* head) {
//快慢指针
ListNode* slow, * fast;
slow = fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
return true;
}
}
//两个指针始终没有相遇
return false;
}
c
//走三步
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode* head) {
//快慢指针
ListNode* slow, * fast;
slow = fast = head;
while (fast && fast->next)
{
slow = slow->next;
int n = 3;
//fast每次⾛三步
while (n--)//进去3次
{
if (fast->next)
fast = fast->next;
else
//不带环
return false;
}
if (slow == fast)
{
return true;
}
}
//两个指针没有相遇
return false;
}
2.9 环形链表II
结论
让⼀个指针(pcur)从链表起始位置开始遍历链表,同时让⼀个指针(next)从判环时相遇点(meet)的位置开始绕环运⾏,两个指针都是每次均走⼀步,最终肯定会在入口点的位置相遇。
第一步,找环的相遇点
第二步,从头结点和相遇点开始遍历,每次都走一步
第三步,当pcur和meet相遇时,即入口点
c
单链表算法题----环形链表II
//先运用找相遇点代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
ListNode* FindNode(ListNode* head)
{
ListNode* fast, * slow;
slow = fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
return slow;//相遇了
}
return NULL;
}
struct ListNode* detectCycle(struct ListNode* head) {
//找环的相遇点
ListNode* meet = FindNode(head);
//从头结点和相遇点开始遍历,每次都走一步
ListNode* pcur = head;
while (meet && pcur)
{
//当pcur和meet相遇时,即入口点
if (meet == pcur)
return meet;
meet = meet->next;
pcur = pcur->next;
}
//链表不带环
return NULL;
}
2.10随机链表的复制
思路
第一步,在原链表基础上继续复制链表
第二步,置random指针,copy->random=pcur->random->next
第三步,复制链表与原链表断开
`
`附上几张图便于理解
第三步的时候 下图
c
单链表算法题----随机链表的复制
/**
* Definition for a Node.
* struct Node {
* int val;
* struct Node *next;
* struct Node *random;
* };
*/
typedef struct Node Node;
Node* BuyNode(int x)
{
Node* newnode = (Node*)malloc(sizeof(Node));
newnode->val = x;
newnode->next = newnode->random = NULL;
return newnode;
}
//原链表传过来,复制链表
void AddNode(Node* phead)
{
Node* pcur = phead;
while (pcur)
{
Node* ret = pcur->next;
//创建新节点,尾插到pcur
Node* newnode = BuyNode(pcur->val);
pcur->next = newnode;
newnode->next = ret;
pcur = ret;
}
}
struct Node* copyRandomList(struct Node* head) {
if (head == NULL)
return NULL;
//第一步
AddNode(head);
//第二步
Node* copy, * pcur, * p1, * newhead, * newtail;
pcur = head;
newhead = newtail = pcur->next;
p1 = pcur;
while (pcur)
{
copy = pcur->next;
if (pcur->random != NULL)
{
//如果为空,copy->random本来就是null,不用再改了
copy->random = pcur->random->next;
}
pcur = copy->next;
}
//第三步
//让pcur再回到头结点,所以有了p1
while (p1->next->next)
{
p1 = p1->next->next;
newtail->next = p1->next;
newtail = newtail->next;
}
return newhead;
}
``
更多链表算法刷题⼊⼝:
⽜客⽹:https://www.nowcoder.com/exam/oj
LeetCode:https://leetcode.cn/problems/copy-list-with-random-pointer/description/