有关链表的题目

本文介绍了如何在环形链表上解决约瑟夫问题,使用快慢指针法找到链表中间节点,合并两个有序链表,反转链表以及移除链表中特定元素的算法。这些技术在LeetCode等编程挑战中常见。
摘要由CSDN通过智能技术生成

目录

1.环形链表的约瑟夫问题

2.链表的中间节点

3.合并两个有序链表

4.反转链表

 5.移除链表元素


1.环形链表的约瑟夫问题

环形链表的约瑟夫问题_牛客题霸_牛客网 (nowcoder.com)

 

 思路:题目给出结构是环形链表,且题目已经定义好了环形链表的结构。

1.创建环形链表,对应数据为1~n。

2.定义一个变量i从1开始数,当i =m时就将该节点释放并重新连接链表。

3.直到单个节点成环时跳出循环,该节点的数据val即为幸存编号。 

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param n int整型 
 * @param m int整型 
 * @return int整型
 */

#include <stdlib.h>
#include <stdio.h>
typedef struct ListNode ListNode;

ListNode* BuyNode(int n)
{
    ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
    newnode->val = n;
    newnode->next = NULL;
    return newnode;
}

ListNode* CreatList(int n)
{
   ListNode* phead = BuyNode(1);
   ListNode* ptail = phead;
   for(int i = 2; i <= n; i++)
   {
    ListNode* newnode = BuyNode(i);
    ptail->next = newnode;
    ptail = ptail->next;
   }
   ptail->next = phead;
   return ptail;
}

int ysf(int n, int m ) {
    // write code here
    ListNode* prev = CreatList(n);
    ListNode* pcur = prev->next;
    int i = 1;
    while(pcur->next != pcur)
    {

        if(i == m)
        {
            prev->next = pcur->next;
            free(pcur);
            pcur = prev->next;
            i = 1;
        }
        else
        {
            prev = pcur;
            pcur = pcur->next;
            i++;
        }
    }
    return pcur->val;
}

 需要注意的是当m=1是,最后一个人就是幸存者。

2.链表的中间节点

876. 链表的中间结点 - 力扣(LeetCode)

 思路:快慢指针法,快指针一次走一步,慢指针一次走两步。

当链表节点为奇数个时,循环结束标志是fast->next == NULL;

当链表节点为偶数个时,循环结束标志是fast == NULL;

要注意循环条件的前后顺序,&&会进行短路求值,如果写成(fast->next && fast),当链表节点为偶数个时,此时fast == NULL,很明显NULL->next是错误的。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    while(fast && fast->next)//注意这里短路,要注意顺序
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

3.合并两个有序链表

21. 合并两个有序链表 - 力扣(LeetCode)

 思路:创建一个新链表,给定两个指针遍历两条原链表,小的插入。当有剩余的链表时,直接将剩余的全部一起尾插到新链表中,无需一个一个尾插,因为原链表是有序的。

注意:会有一个原链表为空的情况,直接返回另一个原链表。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if(list1 == NULL)
    {
        return list2;
    }
    if(list2 == NULL)
    {
        return list1;
    }
    ListNode* plist = NULL;
    ListNode* ptail = NULL;
    while(list1 && list2)
    {
        if(list1->val < list2->val)
        {
            if(plist == NULL)
            {
                    plist = ptail = list1;
                    list1 = list1->next;
            }
            else
            {
                ptail->next = list1;
                ptail = ptail->next;
                list1 = list1->next;
            }
        }
        else
        {
            if(plist == NULL)
            {
                plist = ptail = list2;
                list2 = list2->next;
            }
            else
            {
                ptail->next = list2;
                ptail = ptail->next;
                list2 = list2->next;
            }
        }
    }
    if(list1)
    {
        ptail->next = list1;
    }
    if(list2)
    {
        ptail->next = list2;
    }
    return plist;
}

4.反转链表

206. 反转链表 - 力扣(LeetCode)

 思路:创建新链表,一个一个头插,要注意连接顺序。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode; 
struct ListNode* reverseList(struct ListNode* head) {
    ListNode* plist = NULL;
    ListNode* pcur = head;
    while(pcur)
    {
        if(plist == NULL)
        {
            plist = head;
            pcur = pcur->next; 
            plist->next = NULL;
        }
        else
        {
            ListNode* temp = pcur->next;
            pcur->next = plist;
            plist = pcur;
            pcur = temp;
        }
    }
    return plist;
}

 5.移除链表元素

203. 移除链表元素 - 力扣(LeetCode)

 思路:创建一个新链表,newhead指向新链表的头节点,newtail指向当前链表的尾节点;

pcur遍历原链表,遇到val跳过,遇到非val链接到新链表。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode* newhead = NULL;
    struct ListNode* newtail = NULL;
    struct ListNode* pcur = head;
    while(pcur)
    {
        if(pcur->val != val)
        {
            if(newhead == NULL)
            {
                newhead = newtail = pcur;
            }
            else
            {
                newtail->next = pcur;
                newtail = pcur;
            }
        }
        pcur = pcur->next;
    }
    if(newtail)
    {
        newtail->next = NULL;
    }
    return newhead;
}

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值