【初阶数据结构】顺序表和链表算法题(下)

链表

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/
相关推荐
古希腊掌管学习的神26 分钟前
[搜广推]王树森推荐系统笔记——曝光过滤 & Bloom Filter
算法·推荐算法
qystca27 分钟前
洛谷 P1706 全排列问题 C语言
算法
浊酒南街33 分钟前
决策树(理论知识1)
算法·决策树·机器学习
就爱学编程40 分钟前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
学术头条1 小时前
清华、智谱团队:探索 RLHF 的 scaling laws
人工智能·深度学习·算法·机器学习·语言模型·计算语言学
Schwertlilien1 小时前
图像处理-Ch4-频率域处理
算法
IT猿手2 小时前
最新高性能多目标优化算法:多目标麋鹿优化算法(MOEHO)求解TP1-TP10及工程应用---盘式制动器设计,提供完整MATLAB代码
开发语言·深度学习·算法·机器学习·matlab·多目标算法
__lost2 小时前
MATLAB直接推导函数的导函数和积分形式(具体方法和用例)
数学·算法·matlab·微积分·高等数学
thesky1234562 小时前
活着就好20241224
学习·算法
ALISHENGYA2 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战项目二)
数据结构·c++·算法