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

来源:互联网 发布:程序员翻墙干什么 编辑:程序博客网 时间:2024/06/01 09:46

算法设计与分析(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
原创粉丝点击