顺序表链表经典算法题

1.链表反转

复制代码
typedef struct ListNode listnode;
struct ListNode* reverseList(struct ListNode* head) 
{
    if(head == NULL)
    {
        return head;
    }
    listnode* p1 = NULL;
    listnode* p2 = head;
    listnode* p3 = head->next;
    while(p2)
    {
        p2->next = p1;
        p1 = p2;
        p2 = p3;
        if(p3)
        p3 = p3->next;
    }
    return p1;
}

核心思想:定义三个指针,第一个只想为空,第二个指向头节点,第三个指向头节点的下一个节点。之后让头节点的next指针反转180°,三个指针依次往后走。循环这一过程,直到p2为空。

要注意的是p3为空时不能解引用,否则编译器会报错。

2.移除链表元素

复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeElements(struct ListNode* head, int val) 
{

    struct ListNode* phead = NULL;
    struct ListNode* ptail = NULL;
    struct ListNode* pcur = head;
    while(pcur)
    {
         if(pcur->val != val)
         {
            if(phead == NULL)
            {
                phead = ptail = pcur;
            }
            else 
            {
                ptail->next = pcur;
                ptail = ptail->next;
            }
         }
         pcur = pcur->next;
    }
    if(ptail)
    ptail->next = NULL;
    return phead;
}

核心思想: 遍历链表,把pcur->val = val的节点跳过。最后尾节点的next指针指向空。

3.链表的中间节点

复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode listnode;
struct ListNode* middleNode(struct ListNode* head) 
{
    listnode* man = head;
    listnode* kuai = head;
    while(kuai && kuai->next)
    {
        man = man->next;
        kuai = kuai->next->next;
    }
    return man;
}

核心思想:快慢指针

快指针每次移动两个单位,慢指针每次移动一个单位。这样,快指针指向空或者快指针的next指针指向空时。满指针指向的节点即为中间节点。

4.合并两个有序链表

复制代码
/**
 * 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) 
{
    ListNode* l1 = list1;
    ListNode* l2 = list2;
    if(l1 == NULL)
    return l2;
    if(l2 == NULL)
    return l1;
    ListNode* newhead = NULL;
    ListNode* newtail = NULL;
    while(l1 && l2)
    {
        if(l1->val > l2->val)
        {
            if(newhead == NULL)
            {
                newhead = newtail = l2;
            }
            else
            {
                newtail->next = l2;
                newtail = newtail->next;
            }
            l2 = l2->next;
        }
        else
        {
            if(newhead == NULL)
            {
                newhead = newtail = l1;
            }
            else
            {
                newtail->next = l1;
                newtail = newtail->next;
            }
            l1 = l1->next;
        }
    }
    if(l1)
    newtail->next = l1;
    if(l2)
    newtail->next = l2;
    return newhead;

}

核心思想: 遍历两个链表,比较两链表节点的val值大小,将尾节点的next指针指向较小的节点,直到l1或者l2有一个为空时跳出循环。最后将没有走到空的链表尾插进来。

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

复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
struct ListNode
{
    int val;
    struct ListNode* next;
};
typedef struct ListNode ListNode;
ListNode* ByNode(int x)
{
    ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
    if (newnode == NULL)
    {
        perror("malloc");
        exit(1);
    }
    newnode->val = x;
    newnode->next = NULL;
    return newnode;
}
ListNode* List(int n)
{
    ListNode* phead = ByNode(1);
    ListNode* ptail = phead;
    for (int i = 2; i <= n; i++)
    {
        ptail->next = ByNode(i);
        ptail = ptail->next;
    }
    ptail->next = phead;
    return ptail;
}
int ysf(int m, int n)
{
    ListNode* perv = List(n);
    ListNode* pcur = perv->next;
    int count = 1;
    while (pcur->next != pcur)
    {
        if (count != m)
        {
            perv = pcur;
            pcur = pcur->next;
            count++;
        }
        else
        {
            perv->next = pcur->next;
            free(pcur);
            pcur = perv->next;
            count = 1;
        }

    }
    return pcur->val;
}
int main()
{
    int m, n;
    scanf("%d%d", &n, &m);
    int ret = ysf(m, n);
    printf("%d", ret);
    return 0;
}

主要思路:首先需要创建一个环形链表,然会创建一个指针pcur指向头节点,用pcur来遍历链表,如果count的值等于m,就需要把该节点释放,释放之前要将perv的next指针指向pcur的下一个节点。随后pcur向后移动,count重新置1。如果count的值不等于m,则不需要释放节点,只需把perv和pcur向后移动即可。同时count++。

相关推荐
萧行之26 分钟前
可视化技术复盘:从图形语法看 D3、Vega-Lite、ECharts、Observable Plot
前端·学习·数据可视化
尾善爱看海8 小时前
Vue 面试收官篇:SSR、性能优化落地、30 道高频面试题精讲(附标准答案)
前端·javascript·vue.js·面试·vue
v_34836087628 小时前
Android native端 堆栈打印
android·算法
residual_fan8 小时前
【学术论文】航空发动机故障诊断智能体:基于持续对比强化学习的动态优化方法
人工智能·算法·数据挖掘·数据分析
驳是9 小时前
一个组件,提升 react-router 开发的幸福感
前端·preact
GreenTea9 小时前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
星云API技术支持9 小时前
企业微信二次开发:群权限设置、成员管理与群资料维护的接口组合实践
java·前端·企业微信
京东云开发者9 小时前
81.8 秒的视频,我们改了 15 个版本:一次纯 Codex 驱动的 AI-native 视频实践
前端·aigc
深圳满意度咨询10 小时前
医院满意度数字化测评系统:从数据采集到智能决策的技术实践
算法
Csvn10 小时前
TypeScript 大型项目架构:从单体 tsconfig 到分层可扩展的工程
前端