😽 PREFACE
🎁欢迎各位→点赞 👍 + 收藏 ⭐ + 评论 📝
📢系列专栏: 数据结构刷题集
🔊本专栏涉及到题目是数据结构专栏的补充与应用,只更新相关题目,旨在帮助提高代码熟练度
💪 种一棵树最好是十年前其次是现在
移除链表元素
题目链接:https://leetcode.cn/problems/remove-linked-list-elements/description/
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* prev=NULL,*cur=head;
while(cur)
{
if(cur->val==val)
{
prev->next=cur->next;
free(cur);
cur=prev->next;
}
else
{
prev=cur;
cur=cur->next;
}
}
return head;
}
提交一下,我们会发现执行出错。
正确代码:
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* prev=NULL,*cur=head;
while(cur)
{
if(cur->val==val)
{
if(cur==head)
{
//头删
head=cur->next;
free(cur);
cur=head;
}
else
{
prev->next=cur->next;
free(cur);
cur=prev->next;
}
}
else
{
prev=cur;
cur=cur->next;
}
}
return head;
}
链表的中间结点
题目链接:https://leetcode.cn/problems/middle-of-the-linked-list/description/
正确代码:
//尺取法
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* slow=head,*fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
链表中倒数第k个结点
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
struct ListNode* fast=pListHead,*slow=pListHead;
while(k--)
{
fast=fast->next;
}
while(fast)
{
slow=slow->next;
fast=fast->next;
}
return slow;;
}
结果代码运行不过:
正确代码:
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
struct ListNode* fast=pListHead,*slow=pListHead;
while(k--)
{
if(fast==NULL)//防止越界
{
return NULL;
}
fast=fast->next;
}
while(fast)
{
slow=slow->next;
fast=fast->next;
}
return slow;;
}
反转链表
题目链接:https://leetcode.cn/problems/reverse-linked-list/description/
法一:画图+迭代
//画图+迭代
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* prev,*cur,*next;
prev=NULL,cur=head,next=head->next;
while(cur)
{
//反转
cur->next=prev;
//迭代
prev=cur;
cur=next;
next=next->next;
}
return prev;
}
这个只是最基本的逻辑,一运行发现还是过不了
//画图+迭代
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* prev,*cur,*next;
prev=NULL,cur=head,next=head->next;
while(cur)
{
//反转
cur->next=prev;
//迭代
prev=cur;
cur=next;
if(next)
next=next->next;
}
return prev;
}
再次提交,发现还是过不去:
正确代码1:
//画图+迭代
struct ListNode* reverseList(struct ListNode* head){
if(head==NULL)
return NULL;
struct ListNode* prev,*cur,*next;
prev=NULL,cur=head,next=head->next;
while(cur)
{
//反转
cur->next=prev;
//迭代
prev=cur;
cur=next;
if(next)
next=next->next;
}
return prev;
}
法二:头插
为什么能想到头插呢?因为头插的顺序与链表的顺序刚好相反。
正确代码2:
//头插
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* cur=head, *newhead=NULL;
while(cur)
{
struct ListNode* next=cur->next;
//头插
cur->next=newhead;
newhead=cur;
cur=next;
}
return newhead;
}
合并两个有序链表
题目链接:https://leetcode.cn/problems/merge-two-sorted-lists/description/
法一:不带哨兵位头结点
//不带哨兵位头结点
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode* cur1=list1,*cur2=list2;
struct ListNode* head=NULL,*tail=NULL;
while(cur1&&cur2)
{
if(cur1->val<cur2->val)
{
if(head==NULL)
{
head=tail=cur1;
}
else
{
tail->next=cur1;
tail=tail->next;
}
cur1=cur1->next;
}
else
{
if(head==NULL)
{
head=tail=cur2;
}
else
{
tail->next=cur2;
tail=tail->next;
}
cur2=cur2->next;
}
}
if(cur1)
{
tail->next=cur1;
}
if(cur2)
{
tail->next=cur2;
}
return head;
}
正确代码1:
//不带哨兵位头结点
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
//如果链表为空,返回另一个
if(list1==NULL)
{
return list2;
}
if(list2==NULL)
{
return list1;
}
struct ListNode* cur1=list1,*cur2=list2;
struct ListNode* head=NULL,*tail=NULL;
while(cur1&&cur2)
{
if(cur1->val<cur2->val)
{
if(head==NULL)
{
head=tail=cur1;
}
else
{
tail->next=cur1;
tail=tail->next;
}
cur1=cur1->next;
}
else
{
if(head==NULL)
{
head=tail=cur2;
}
else
{
tail->next=cur2;
tail=tail->next;
}
cur2=cur2->next;
}
}
if(cur1)
{
tail->next=cur1;
}
if(cur2)
{
tail->next=cur2;
}
return head;
}
法二:带哨兵位头结点
正确代码2:
//带哨兵位头结点
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode* cur1=list1,*cur2=list2;
struct ListNode* guard=NULL,*tail=NULL;
guard=tail=(struct ListNode*)malloc(sizeof(struct ListNode));
tail->next=NULL;
while(cur1&&cur2)
{
if(cur1->val<cur2->val)
{
tail->next=cur1;
tail=tail->next;
cur1=cur1->next;
}
else
{
tail->next=cur2;
tail=tail->next;
cur2=cur2->next;
}
}
if(cur1)
{
tail->next=cur1;
}
if(cur2)
{
tail->next=cur2;
}
struct ListNode* head=guard->next;//防止内存泄漏
free(guard);
return head;
}
链表分割
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
struct ListNode* lessguard,*lesstail,*greaterguard,*greatertail;
lessguard=lesstail=(struct ListNode*)malloc(sizeof(struct ListNode));
greaterguard=greatertail=(struct ListNode*)malloc(sizeof(struct ListNode));
lesstail->next=greatertail->next=NULL;
struct ListNode* cur=pHead;
while(cur)
{
if(cur->val<x)
{
lesstail->next=cur;
lesstail=lesstail->next;
}
else
{
greatertail->next=cur;
greatertail=greatertail->next;
}
cur=cur->next;
}
lesstail->next=greaterguard->next;
pHead=lessguard->next;
free(greaterguard);
free(lessguard);
return pHead;
}
};
运行一下:
由于牛客不提供用例错误,我们可以转到力扣官网上查。当然了,也可以把我们写的用例往代码带,看看哪出错了。
正确代码:
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
struct ListNode* lessguard,*lesstail,*greaterguard,*greatertail;
lessguard=lesstail=(struct ListNode*)malloc(sizeof(struct ListNode));
greaterguard=greatertail=(struct ListNode*)malloc(sizeof(struct ListNode));
lesstail->next=greatertail->next=NULL;
struct ListNode* cur=pHead;
while(cur)
{
if(cur->val<x)
{
lesstail->next=cur;
lesstail=lesstail->next;
}
else
{
greatertail->next=cur;
greatertail=greatertail->next;
}
cur=cur->next;
}
lesstail->next=greaterguard->next;
greatertail->next=NULL;//不能忽略
pHead=lessguard->next;
free(greaterguard);
free(lessguard);
return pHead;
}
};
链表的回文结构
正确代码:
//找中间节点
struct ListNode* middleNode(struct ListNode* head) {
struct ListNode* slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
//反转
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* cur = head;
struct ListNode* newhead = NULL;
while (cur) {
struct ListNode* next = cur->next;
//头插
cur->next = newhead;
//迭代
newhead = cur;
cur = next;
}
return newhead;
}
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
struct ListNode* mid=middleNode(A);
struct ListNode* rHead=reverseList(mid);
struct ListNode* curA=A;
struct ListNode* curR=rHead;
while(curA&&curR)
{
if(curA->val!=curR->val)
{
return false;
}
else
{
curA=curA->next;
curR=curR->next;
}
}
return true;
}
};
相交链表
题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists/description/
正确代码:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* tailA=headA,*tailB=headB;
int lenA=0,lenB=0;
while(tailA)
{
lenA++;
tailA=tailA->next;
}
while(tailB)
{
lenB++;
tailB=tailB->next;
}
//不相交的情况,不写的话leetcode也不会判错
if(tailA!=tailB)
{
return NULL;
}
int gap=abs(lenA-lenB);
struct ListNode* longList=headA,*shortList=headB;
if(lenA<lenB)
{
longList=headB;
shortList=headA;
}
while(gap--)
{
longList=longList->next;
}
while(longList!=shortList)
{
longList=longList->next;
shortList=shortList->next;
}
return shortList;
}
环形链表
题目链接:https://leetcode.cn/problems/linked-list-cycle/description/
正确代码:
bool hasCycle(struct ListNode *head) {
struct ListNode* slow=head,*fast=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
{
return true;
}
}
return false;
}
环形链表II
题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/description/
法一:双指针
正确代码1:
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow=head,*fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
//相遇
struct ListNode* meetNode=slow;
//公式
while(meetNode!=head)
{
meetNode=meetNode->next;
head=head->next;
}
return head;
}
}
return NULL;
}
法二:转化成链表相交
正确代码2:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* tailA=headA,*tailB=headB;
int lenA=0,lenB=0;
while(tailA)
{
lenA++;
tailA=tailA->next;
}
while(tailB)
{
lenB++;
tailB=tailB->next;
}
//不相交的情况,不写的话leetcode也不会判错
if(tailA!=tailB)
{
return NULL;
}
int gap=abs(lenA-lenB);
struct ListNode* longList=headA,*shortList=headB;
if(lenA<lenB)
{
longList=headB;
shortList=headA;
}
while(gap--)
{
longList=longList->next;
}
while(longList!=shortList)
{
longList=longList->next;
shortList=shortList->next;
}
return shortList;
}
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow=head,*fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
struct ListNode* meetNode=slow;
struct ListNode* list1=meetNode->next;
struct ListNode* list2=head;
meetNode->next=NULL;
return getIntersectionNode(list1,list2);
}
}
return NULL;
}
复制带随机指针的链表
题目链接:https://leetcode.cn/problems/copy-list-with-random-pointer/description/
正确代码:
struct Node* copyRandomList(struct Node* head) {
//1.拷贝结点插入原结点的后面
struct Node* cur=head;
while(cur)//遍历整个链表
{
//插入
struct Node* copy=(struct Node*)malloc(sizeof(struct Node));
copy->val=cur->val;
struct Node* next=cur->next;
//cur copy next
cur->next=copy;
copy->next=next;
cur=next;
}
//2.拷贝random结点
cur=head;
while(cur)
{
struct Node* copy=cur->next;
if(cur->random==NULL)
{
copy->random=NULL;
}
else
{
copy->random=cur->random->next;
}
cur=cur->next->next;
}
//3.拆组
struct Node* copyHead=NULL,*copyTail=NULL;
cur=head;
while(cur)
{
struct Node* copy=cur->next;
struct Node* next=copy->next;
//copy尾插
if(copyHead==NULL)
{
copyHead=copyTail=copy;
}
else
{
copyTail->next=copy;
copyTail=copyTail->next;
}
//恢复原链表
cur->next=next;
cur=next;
}
return copyHead;
}