算法设计与分析(18)-- Reverse Nodes in k-Group(难度:Hard)

算法设计与分析(18)

题目:Reverse Nodes in k-Group

https://leetcode.com/problems/reverse-nodes-in-k-group/#/description
问题描述:
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.

k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.

You may not alter the values in the nodes, only nodes itself may be changed.

Only constant memory is allowed.

For example, Given this linked list: 1->2->3->4->5

For k = 2, you should return: 2->1->4->3->5

For k = 3, you should return: 3->2->1->4->5

算法思路:

给一链表,题目要求以k为一组将此链表的节点翻转,并且要求不改变节点内的值,只能改变节点next的取值。这里的算法并不难,可以理解为把链表分为多个以k为长度的小链表,把每个小链表翻转,然后重新接上得到最后的链表。并且最后一条长度不足k的小链表不需要翻转。
这里给出也是如此的思路,我们从头部开始处理,可以用ListNode *first, *second分别指向需要翻转的长度为k的小链表的头部和尾部,然后翻转此小链表,在寻找下一个小链表,直到翻转了所有的小链表。

(1)需要翻转长度为k的链表,首先定义函数ListNode* ExistNextK(ListNode* first, int k) ,判断从当前节点ListNode *first开始是否存在第k个节点,如果存在,返回第k个节点指针,否则返回NULL:

ListNode* ExistNextK(ListNode* first, int k)
{
    if (first == NULL)
        return NULL;
    int count = 1;
    while (first->next != NULL && count < k)
    {
        first = first->next;
        count++;
    }
    if (count == k)
        return first;
    else
        return NULL;
}

(2)然后开始写函数ListNode* reverseKGroup(ListNode* head, int k) .

a)若head为NULL或者k==1,直接返回head;

if (head == NULL || k == 1)
    return head;

b)初始化指针first,second,temp;其中first和second指向需要翻转的小链表的头部和尾部。那么temp指针的作用是:当我们翻转完一个小链表,first和second会指向下一个小链表,这是需要temp记录上一个小链表的尾部,以连接下一个小链表翻转后的头部。

ListNode *first = head, *second = NULL, *temp = NULL;

c)用while条件判断是否有下一个需要翻转的小链表:

while ( second = ExistNextK(first, k))

在while中,若当前first为head,那么head重新取为second,若不是,测temp->next取为second:

if (first == head)
    head = second;
else
    temp->next = second;

然后使用取ListNode *temp1 = first, *temp2 = temp1->next, *temp3 = temp2->next; 使用temp1,temp2,temp3对小链表进行翻转操作。
这里使用temp2 != second判断是否翻转到小链表的尾部,当temp2 == second成立,直接temp2->next = temp1;翻转最后一段。
然后使用temp记录这一段小链表的尾部,并且更新first指向下一段小链表的头部:

first->next = second->next;
while (temp2 != second)
{
    temp2->next = temp1;
    temp1 = temp2;
    temp2 = temp3;
    temp3 = temp3->next;
}
temp2->next = temp1;
temp = first;
first = temp3;

(3)最后返回head。

程序运行结果:

这里写图片描述

这里写图片描述

实现代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

ListNode* ExistNextK(ListNode* first, int k)
{
    if (first == NULL)
        return NULL;
    int count = 1;
    while (first->next != NULL && count < k)
    {
        first = first->next;
        count++;
    }
    if (count == k)
        return first;
    else
        return NULL;
}

class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) 
{
    if (head == NULL || k == 1)
        return head;

    ListNode *first = head, *second = NULL, *temp = NULL;

    while ( second = ExistNextK(first, k))
    {

        if (first == head)
            head = second;
        else
            temp->next = second;

        ListNode *temp1 = first, *temp2 = temp1->next, *temp3 = temp2->next;
        first->next = second->next;
        while (temp2 != second)
        {
            temp2->next = temp1;
            temp1 = temp2;
            temp2 = temp3;
            temp3 = temp3->next;
        }
        temp2->next = temp1;
        temp = first;
        first = temp3;
    }

    return head;
}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值