IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 爆刷leetcode——链表(三) -> 正文阅读

[数据结构与算法]爆刷leetcode——链表(三)


725. 分隔链表

这里是引用

判断可能存在的情况:
1.链表恰好能被完整分割成k份;
2.链表无法被分割成k份;
3.链表可以被分割成k份,但仍有剩余节点;
思路:
首先求出链表的总长度,判断能否被完整分割成k份;如果链表可以被分割成k份,但仍有剩余,那么前面的几个链表每个就得多得一个节点;如果无法被分割成k份,那么我们就得将每个节点分成单个链表,然后再将无法被分割出来的链表置为NULL;

int GetListLen(struct ListNode* head)
{
    struct ListNode* cur = head;
    int len = 0;
    while(cur)
    {
        len++;
        cur = cur->next;
    }
    return len;
}

struct ListNode** splitListToParts(struct ListNode* head, int k, int* returnSize)
{
    struct ListNode** lists = (struct ListNode**)malloc(sizeof(struct ListNode*) * k);
    *returnSize = k;

    //获取链表长度
    int list_len = GetListLen(head);
    
    //剩余节点
    int remain_node = list_len % k;
    //遍历链表
    struct ListNode* cur = head, *new_head = head;   
    int i = 0; 
    
    int ans = k;
    int flag = 1;
    //无法被分割成k份,那么就得将修改分割次数
    if(list_len < k)
    {
        ans = list_len;
    }
    
    while(ans--)
    {
        //平均下来每个链表的长度
        int ListLen = list_len / k;
        //将剩余节点一一分配给前面的链表
        if(remain_node)
        {
            ListLen = list_len / k + 1;
            remain_node--;
        }
        
        //遍历链表,到达要断开的位置
        while(--ListLen)
        {
            cur = cur->next;
        }

        //将链表断开,添加入结果
        struct ListNode* next = cur->next;
        cur->next = NULL;
        lists[i] = new_head;
        //刷新下一个链表的起点
        cur = next;
        new_head = next;
        i++;
    }

    //将无法分割出来的链表置为NULL
    for(int j = i; j < k; j++)
    {
        lists[j] = NULL;
    }

    return lists;
}

1670. 设计前中后队列

这里是引用

思路:
这道题的难点主要在于对中间节点的增删,题目提到如果有两个中间节点,那么我们要去前面的节点进行操作,也就是说:在插入后,节点数如果为奇数,该节点应该正好在中间;如果插入后节点数为偶数,该节点为两个中间节点的较前一个; 删除也是同理:在删除时,如果节点数为奇数,我们就删除正中间的那个;如果为偶数,我们就删除两个节点的较前一个;
我们设计一个函数,来获取中间节点的前一个节点指针:

//找到中间节点的前一个节点
Node* GetMidPrevNode(FrontMiddleBackQueue* obj)
{
    Node* slow = obj->head, *fast = obj->head, *prev = NULL;

    while(fast && fast->next)
    {
        prev = slow;
        slow = slow->next;
        fast = fast->next->next;
    }

    return prev;
}

在这里插入图片描述
当删除中间节点时,如果节点数为偶数,这个函数将会向我们提供两个中间节点的较前一个节点;如果节点数为奇数,它会提供给我们正中间节点的前一个结点的指针;所以我们需要根据节点数来判断要删除的中间节点究竟是哪一个。
注意:我们在插入时需要对节点数为1时的队列进行特殊判断,因为中间节点此时应该插在队列的头部,这会改变头节点的指向;在删除时,需要对节点数小于等于2的队列进行特殊判断,因为此时中间节点都为头节点,删除它也会改变头节点的指向;

typedef struct Node
{
    struct Node* next;
    int val;
}Node;


typedef struct 
{
    Node* head;//头部
    Node* tail;//尾部
    int size;//记录当前元素个数
} FrontMiddleBackQueue;

//创建新节点
Node* CreateNewNode(int val)
{
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->next = NULL;
    new_node->val = val;

    return new_node;
}

//判空
bool QueueEmpty(FrontMiddleBackQueue* obj)
{
    return obj->size == 0;
}

//找到中间节点的前一个节点
Node* GetMidPrevNode(FrontMiddleBackQueue* obj)
{
    Node* slow = obj->head, *fast = obj->head, *prev = NULL;

    while(fast && fast->next)
    {
        prev = slow;
        slow = slow->next;
        fast = fast->next->next;
    }

    return prev;
}

//找到要删除的中间节点的前一个
Node* FindNodePrev(FrontMiddleBackQueue* obj, Node* mid)
{
    Node* cur = obj->head;
    while(cur && cur->next != mid)
    {
        cur = cur->next;
    }

    return cur;
}

FrontMiddleBackQueue* frontMiddleBackQueueCreate() 
{
    FrontMiddleBackQueue* obj = (FrontMiddleBackQueue*)malloc(sizeof(FrontMiddleBackQueue));
    obj->head = obj->tail = NULL;
    obj->size = 0;
    
    return obj;
}

void frontMiddleBackQueuePushFront(FrontMiddleBackQueue* obj, int val) 
{
    //创建新节点
    Node* new_node = CreateNewNode(val);

    //如果队列为空
    if(QueueEmpty(obj))
    {
        //头尾指向同一元素
        obj->head = obj->tail = new_node;
    }    
    else
    {
        new_node->next = obj->head;
        obj->head = new_node;
    }

    obj->size++;
}

void frontMiddleBackQueuePushMiddle(FrontMiddleBackQueue* obj, int val) 
{
    Node* mid_prev = GetMidPrevNode(obj);
    Node* new_node = CreateNewNode(val);

    //选择在中间节点的右边进行插入,确保:
    //1.当有两个中间位置时,其能在较前面
    //2.当只有一个中间节点时,其在正中间
    
    //队列为空
    if(QueueEmpty(obj))
        obj->head = obj->tail = new_node;

    //当只有一个节点时,采用头插
    else if(obj->size == 1)
    {
        frontMiddleBackQueuePushFront(obj,val);
        return;
    }
    
    //当有两个及以上节点
    else
    {
        new_node->next = mid_prev->next;
        mid_prev->next = new_node;
    }

    obj->size++;
}

void frontMiddleBackQueuePushBack(FrontMiddleBackQueue* obj, int val) 
{
    Node* new_node = CreateNewNode(val);
    
    //如果队列为空
    if(QueueEmpty(obj))
        obj->head = obj->tail = new_node;

    //有一个及以上节点
    else
    {
        obj->tail->next = new_node;
        obj->tail = new_node;
    }
    
    obj->size++;
}

int frontMiddleBackQueuePopFront(FrontMiddleBackQueue* obj)
{
    //队列为空
    if(QueueEmpty(obj))
        return -1;

    int tmp = obj->head->val;
    //只有一个节点
    if(obj->size == 1)
    {
        free(obj->head);
        obj->head = obj->tail = NULL;
    }
    //两个及以上节点
    else
    {
        Node* new_head = obj->head->next;
        free(obj->head);
        obj->head = new_head;
    }

    obj->size--;

    return tmp;
}

int frontMiddleBackQueuePopMiddle(FrontMiddleBackQueue* obj) 
{
    if(QueueEmpty(obj))
        return -1;

    //该函数如果在偶数个情况下,返回两个中间位置的较前一个
    //在奇数情况下,返回中间节点的前一个

    Node* mid = GetMidNode(obj);

    int tmp = 0;
    //如果只有一个或两个节点,调用头删
    //当只有一个或两个节点时,中间节点为首节点
    if(obj->size == 1 || obj->size == 2)
    {
        return frontMiddleBackQueuePopFront(obj);
        
    }
    else
    {   
        if(obj->size % 2 == 1)
            mid = mid->next;

        tmp = mid->val;
        
        //找到要删除的节点的前一个
        Node* prev = FindNodePrev(obj,mid);
        prev->next = mid->next;
        free(mid);
    }
    
    obj->size--;
    return tmp;
}

int frontMiddleBackQueuePopBack(FrontMiddleBackQueue* obj) 
{
    if(QueueEmpty(obj))
        return -1;

    int tmp = obj->tail->val;
    if(obj->size == 1)
        obj->head = obj->tail = NULL;
    else
    {
        Node* prev = FindNodePrev(obj,obj->tail);
        prev->next = NULL;
        free(obj->tail);
        obj->tail = prev;
    }

    obj->size--;
    return tmp;
}

void frontMiddleBackQueueFree(FrontMiddleBackQueue* obj) 
{
    Node* cur = obj->head;
    while(cur)
    {
        Node* next = cur->next;
        free(cur);
        
        cur = next;
    }
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 11:43:26  更:2022-09-13 11:48:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:32:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码