数据结构——单链表OJ题

在这里插入图片描述


前言

在前面的博客中我们知道了什么是单链表以及如何建立单链表!
现在让我们来检验一下学习成果吧!

提示:此博客中题目均来自牛客网以及力扣网!在题目中我会附带两大网站的链接,大家也可以去练习一下!
若有链接问题可以在评论区及时反馈!


一、删除链表中等于给定值 val 的所有节点

题目链接:OJ链接
在这里插入图片描述

提示:
列表中的节点数目在范围 [0, 104] 内
1 <= Node.val <= 50
0 <= val <= 50

思路解析:
在这里插入图片描述

代码演示:

struct ListNode* removeElements(struct ListNode* head, int val) {
    
    
     struct ListNode* newhead = NULL;
     struct ListNode* move = head;
     struct ListNode* tail = NULL;

     while (move != NULL) {
    
    
         if (move->val != val) {
    
    
             if (tail == NULL) {
    
    //如果newnode为NULL,则tail等于newnode,则直接将结点地址赋予tail
                 newhead = tail = move;
                 move = move->next;
             }
             else {
    
    
                 tail->next = move;
                 move = move->next;
                 tail = tail->next;
             }
         }
         else {
    
    
             struct ListNode* temp = move;//新建结点保存要free的地址,以免free后造成节点丢失
             move = move->next;
             free(temp);
         }
     }
     if (tail)//如果新链表不为空,则将其尾结点的next置空
         tail->next = NULL;
     return newhead;
 }

二、反转一个单链表

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述

提示:
链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000

思路解析:
在这里插入图片描述

代码演示:

struct ListNode* reverseList(struct ListNode* head) {
    
    
    struct ListNode* move1 = head;
    struct ListNode* tail = head;
    if (head == NULL || head->next == NULL) {
    
    //如果链表为空或者只有一个结点,则不需要反转
        return tail;
    }
    struct ListNode* move2 = move1->next;
    while (move2) {
    
    
        struct ListNode* temp = move2->next;//保存下一个结点的地址,防止后面的节点丢失
        move2->next = move1;
        move1 = move2;
        move2 = temp;
    }
    tail->next = NULL;//尾结点的next置空
    struct ListNode* newhead = move1;//move1最后指向了反转链表的起始结点
    return newhead;
}

三、返回链表的中间结点

题目链接:OJ链接
在这里插入图片描述

提示:
链表的结点数范围是 [1, 100]
1 <= Node.val <= 100

思路解析:
在这里插入图片描述

代码演示:

struct ListNode* middleNode(struct ListNode* head){
    
    
    struct ListNode*move1=head;
    struct ListNode*move2=head;
    while(move2!=NULL&&move2->next!=NULL){
    
    //此处move2!=NULL和move2->next!=NULL
        move1=move1->next;                //的位置不能交换,否则会造成空指针错误
        move2=move2->next->next;
    }
    return move1;
}

四、输出该链表中倒数第k个结点

题目链接:OJ链接
在这里插入图片描述
思路解析:
在这里插入图片描述

代码演示:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    
    
    
    struct ListNode*move1=pListHead;
    struct ListNode*move2=pListHead;
    int i=k;
    while(i>0&&move2!=NULL){
    
    //move2向后移动k位
        move2=move2->next;
            i--;
    }
    if(move2==NULL&&i>0){
    
    //如果k大于链表结点数目,则返回NULL
        return move2;
    }
    while(move2){
    
    
        move1=move1->next;
        move2=move2->next;
    }
    return move1;
}

五、将两个有序链表合并

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述

提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列

思路解析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码演示:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    
    
    
    struct ListNode*move1=list1;
    struct ListNode*move2=list2;
    struct ListNode*newnode=NULL;
    struct ListNode*tail=NULL;
    while(move1!=NULL&&move2!=NULL){
    
    
        if(move1->val<=move2->val){
    
    
            if(tail==NULL){
    
    {
    
    //如果newnode为NULL,则tail等于newnode,则直接将结点地址赋予tail
            newnode=tail=move1;
            move1=move1->next;
            }
            else{
    
    
                tail->next=move1;
                move1=move1->next;
                tail=tail->next;
            }
        }
        else{
    
    
            if(tail==NULL){
    
    //如果newnode为NULL,则tail等于newnode,则直接将结点地址赋予tail
                newnode=tail=move2;
                move2=move2->next;
            }
            else{
    
    
                tail->next=move2;
                move2=move2->next;
                tail=tail->next;
            }
            }
    }
    if(move1==NULL){
    
    //如果链表1遍历完而链表2没有,则将链表2剩余结点尾插到newnode中
        while(move2!=NULL){
    
    
            if(tail==NULL){
    
    //如果newnode为NULL,则tail等于newnode,则直接将结点地址赋予tail
                newnode=tail=move2;
                move2=move2->next;
            }
            else{
    
    
                tail->next=move2;
                move2=move2->next;
                tail=tail->next;
            }
        }
    }
      if(move2==NULL){
    
    //如果链表2遍历完而链表1没有,则将链表1剩余结点尾插到newnode中
        while(move1!=NULL){
    
    
           if(tail==NULL){
    
    //如果newnode为NULL,则tail等于newnode,则直接将结点地址赋予tail
            newnode=tail=move1;
            move1=move1->next;
            }
            else{
    
    
                tail->next=move1;
                move1=move1->next;
                tail=tail->next;
            }
        }
    }
      return newnode;
}

六、链表的回文结构

题目链接:OJ链接

在这里插入图片描述
思路解析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码演示:

bool chkPalindrome(struct ListNode* A) {
    
    
    struct ListNode* move1 = A;
    struct ListNode* move2 = A;
    struct ListNode* move3 = A;
    struct ListNode* newnode = NULL;
    struct ListNode* tail = NULL;
    while (move2 != NULL&&move2->next != NULL ) {
    
    //找到中间节点
        move1 = move1->next;
        move2 = move2->next->next;
    }
    if (move2 == NULL);//如果节点个数为奇数,则move1向后移动一位
    else {
    
    
        move1 = move1->next;
    }
    while (move1 != NULL) {
    
    //将后半段链表头插到newnode中
        if (newnode == NULL) {
    
    
            newnode = tail = move1;
            move1 = move1->next;
            tail->next = NULL;
        }
        else {
    
    
            struct ListNode* temp = move1->next;
            move1->next = newnode;
            newnode = move1;
            move1 = temp;
        }
    }
    struct ListNode* cmp = newnode;
    while (move3 != NULL && cmp != NULL) {
    
    //比较原链表前半段和newnode是否相同
        if (move3->val != cmp->val) {
    
    
            return 0;
        }
        else {
    
    
            move3 = move3->next;
            cmp = cmp->next;
        }
    }
    return 1;
}

七、将链表分割成两部分

题目链接:OJ链接
在这里插入图片描述
思路解析:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

代码演示:

ListNode* partition(ListNode* pHead, int x) {
    
    
        struct ListNode*head1=(struct ListNode*)malloc(sizeof(struct ListNode));
        struct ListNode*head2=(struct ListNode*)malloc(sizeof(struct ListNode));
        struct ListNode*tail1=head1;
        struct ListNode*tail2=head2;
        struct ListNode*move=pHead;
        while(move){
    
    
            if(move->val<x){
    
    
                tail1->next=move;
                move=move->next;
                tail1=tail1->next;
            }
            else{
    
    
                tail2->next=move;
                move=move->next;
                tail2=tail2->next;
            }
            }
        tail2->next=NULL;//将尾指针的next置空
        tail1->next=head2->next;
        struct ListNode*temp1=head1;
        struct ListNode*temp2=head2;
        head1=head1->next;//指针指向头结点的下一节点
        free(temp1);//释放掉创建的头结点
        free(temp2);
        return head1;
    }

八、找出第一个公共结点

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:
函数返回结果后,链表必须 保持其原始结构 。

思路解析:
在这里插入图片描述
在这里插入图片描述

代码演示:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    
    
    struct ListNode *move1=headA;
    struct ListNode *move2=headB;
    int len1=1,len2=1;
    while(move1){
    
    //得到链表A的长度
        move1=move1->next;
        len1++;
    }
    while(move2){
    
    //得到链表B的长度
        move2=move2->next;
        len2++;
    }
    int k=abs(len1-len2);//取相减的绝对值
    struct ListNode *moveA=headA;
    struct ListNode *moveB=headB;
    if(len1>len2){
    
    //较长的链表走k步
        while(k--){
    
    
            moveA=moveA->next;
        }
    }
      if(len1<len2){
    
    
        while(k--){
    
    
            moveB=moveB->next;
        }
    }
      while(moveA&&moveB){
    
    
        if(moveA==moveB)
            return moveA;//若地址相同则返回
        moveA=moveA->next;
        moveB=moveB->next;
    }
    return NULL;

九、判断链表中是否有环

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述

提示:

链表中节点的数目范围是 [0, 104]
-105 <= Node.val <= 105
pos 为 -1 或者链表中的一个 有效索引 。

思路解析:
在这里插入图片描述

代码演示:

bool hasCycle(struct ListNode *head) {
    
    
    struct ListNode*move1=head;
    struct ListNode*move2=head;
    while(move1&&move2&&move2->next){
    
    //此处move2和move2->next的顺序不可交换
        move1=move1->next;           //否则会导致空指针错误
        move2=move2->next->next;
        if(move1==move2)
            return true;
    }
    return false;
}

总结

这九道单链表OJ都是我见过的很经典的题型!
在这里为大家分享一下!
希望有更多的人能够通过这些题目更好地掌握单链表相关的知识!

猜你喜欢

转载自blog.csdn.net/mdjsmg/article/details/132046363