您现在的位置是:首页 >学无止境 >【Leetcode -328.奇偶链表 - 725.分隔链表】网站首页学无止境

【Leetcode -328.奇偶链表 - 725.分隔链表】

YoungMLet 2023-07-02 04:00:02
简介【Leetcode -328.奇偶链表 - 725.分隔链表】

Leetcode -328.奇偶链表

题目:给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。

请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。

你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

示例 1:
输入: head = [1, 2, 3, 4, 5]
输出 : [1, 3, 5, 2, 4]

示例 2 :
输入: head = [2, 1, 3, 5, 6, 4, 7]
输出 : [2, 3, 6, 7, 1, 5, 4]

我们的思路是,将一个链表分为奇数链表和偶数链表两个部分,最后将奇数链表的尾节点连上偶数链表的头节点;开始头节点为奇数链表的头节点和尾节点,头节点的next为偶数链表的头节点和尾节点;然后依次将奇数链表的尾节点连上偶数链表尾节点的next,因为偶数节点的next就是奇数节点;而偶数链表的尾节点连上奇数链表尾节点的next;

先将奇数链表和偶数链表划分好,奇数链表的尾节点oddtail暂时不处理,奇数链表的头节点为head:
在这里插入图片描述

将奇数链表的尾节点连到偶数链表的头节点:

在这里插入图片描述

当eventail或者eventail->next为空时循环结束,完整的结果图:

在这里插入图片描述

代码注释如下:

		struct ListNode* oddEvenList(struct ListNode* head)
		{
		    if (!head)
		        return head;
		
		    //oddtail为奇数链表的尾,头就是head
		    //evenhead为偶数链表的头,eventail为偶数链表的尾
		    struct ListNode* oddtail = head, * eventail = head->next, * evenhead = head->next;
		
		    while (eventail && eventail->next)
		    {
		        //奇数的尾部连到偶数的next,即连到奇数链表的节点
		        oddtail->next = eventail->next;
		
		        //更新奇数尾部
		        oddtail = oddtail->next;
		
		        //偶数的尾部连到奇数的next,即连到偶数链表的节点
		        eventail->next = oddtail->next;
		
		        //更新偶数尾部
		        eventail = eventail->next;
		    }
		
		    //奇数链表连到偶数链表的头节点
		    oddtail->next = evenhead;
		
		    //返回head,head即为奇数链表的头节点
		    return head;
		}

Leetcode - 725.分隔链表

题目:给你一个头结点为 head 的单链表和一个整数 k ,请你设计一个算法将链表分隔为 k 个连续的部分。

每部分的长度应该尽可能的相等:任意两部分的长度差距不能超过 1 。这可能会导致有些部分为 null 。

这 k 个部分应该按照在链表中出现的顺序排列,并且排在前面的部分的长度应该大于或等于排在后面的长度。

返回一个由上述 k 部分组成的数组。

示例 1:
输入:head = [1, 2, 3], k = 5
输出: [[1], [2], [3], [], []]
解释:
第一个元素 output[0] 为 output[0].val = 1 ,output[0].next = null 。
最后一个元素 output[4] 为 null ,但它作为 ListNode 的字符串表示是[] 。

示例 2:
输入:head = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
输出: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
解释:
输入被分成了几个连续的部分,并且每部分的长度相差不超过 1 。前面部分的长度大于等于后面部分的长度。

我们的思路是,先遍历一次链表计算链表的长度,然后定义两个值确定分隔后每个链表的节点以及是否有多出来的节点,再根据每个链表的节点数往后迭代走;代码以及注释如下:

		struct ListNode** splitListToParts(struct ListNode* head, int k, int* returnSize)
		{
		    struct ListNode* cur = head;
		
		    //计算链表长度
		    int len = 0;
		    while (cur)
		    {
		        len++;
		        cur = cur->next;
		    }
		
		    //使cur回到头节点
		    cur = head;
		
		    //malloc一个二级指针返回
		    struct ListNode** pphead = (struct ListNode**)malloc(sizeof(struct ListNode*) * k);
		
		    //surplus是平分节点之后多出来的个数
		    int surplus = len % k;
		
		    //listnumber是平均分链表之后每个链表里面的节点数
		    int listnumber = len / k;
		
		    //将平均分好的链表放入节点
		    for (int i = 0; i < k; i++)
		    {
		        //用下标访问二级指针,放入第i个下标
		        //cur是原链表的头,先把cur放入二级指针,
		        //如果cur不为空,则使用一个size继续判断是否需要放入cur后面的节点,然后迭代cur
		        pphead[i] = cur;
		
		        
		        if (cur)
		        {
		            //判断是否要放入cur后面的节点
		            int size = listnumber + (surplus-- > 0 ? 1 : 0);
		            for (int j = 0; j < size - 1; j++)
		            {
		                cur = cur->next;
		            }
		
		            //迭代
		            struct ListNode* next = cur->next;
		            cur->next = NULL;
		            cur = next;
		        }
		
		    }
		
		    //返回二级指针的长度
		    *returnSize = k;
		    return pphead;
		}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。