[ LeetCode ] #25. Reverse Nodes in k-Group(翻转相邻的k个元素)

题目:25. Reverse Nodes in k-Group

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.

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

Note:

  • Only constant extra memory is allowed.
  • You may not alter the values in the list's nodes, only nodes itself may be changed.

题意:

给出一个单链表及一个正整数k,将单链表中每连续k个元素反转,如若最后不足k个则按原序输出,返回最终翻转后的结果。

分析:

一道leetcode中难度为hard的题目,解答此题时,受所给样例的干扰,没搞清楚题目直接按k位翻转做了,导致后面各种修改才得以实现。以下为解题时的第一思路及本题所提交的最佳思路。

  1. 首先进行了常规判断,若所给list为空或仅有一个元素 再或者 k为1,那么均可以直接返回list。
  2. 翻转列表常规思路 即使用单链表头插法即可,不过本题要求每k个元素进行翻转,那么就需要由相应的变换,比如每够k个元素时,采用头插法的头节点需要更换。因此,可分为两种情况:1)当前翻转个数如果不够k个,则直接进行头插入即可。2)当前位置之前已经进行了k个元素的翻转,那么这时就需要更新头插法的头节点指向。这里还有一点不同的是,最后不足k个的话,不需要翻转,因此 在此之前对所给链表拷贝了一份(newlist),以便保存后面剩余的有序部分,所以每翻转k个元素,在更新头节点时,同样需要对newlist的指向进行后移操作。
  3. 以上遍历完之后 判断是否需要处理有序部分。如果需要,则直接在结果上追加对应的有序部分,否则将剩余的翻转过后的元素追加到结果链表上。

最佳解法

首先统计单链表的个数,然后先判断当前剩余的个数是否足够k个,足够则进行翻转,否之可以直接返回结果。

Code1 & C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
     	if(head==NULL || head->next==NULL || k==1) return head;
        ListNode *first = head->next, *end = head;
        ListNode *pre = new ListNode(0), *newlist=new ListNode(0), *ans = new ListNode(0);
        ListNode *p = newlist;
        while(end!=NULL){    // 拷贝原始链表
            ListNode *tmp = new ListNode(end->val);
            p->next = tmp;
            p = tmp;
            end = end->next;
        } 
        end = head;
        newlist = newlist->next;
        int i=1;
        pre->next = head;
        end->next = first;
        ans = pre;
        head = ans;// head 指向一个新建的结果链表
        while(first!=NULL){
            if(i<k){    // 正常翻转
                ListNode *tmp = first;
                first = first->next;
                end->next=first;
                tmp->next = pre->next;
                pre->next = tmp;
                ++i;
            }else{
                i=1;
                ans->next = pre->next;    //将上一步翻转后的链表追加到结果链表上
                ans = end;
                pre = end;    //更新头节点
                end = first;
                first = first->next;
                int j=0;
                while(j<k && newlist!=NULL){    // 有序链表同步后移
                    newlist = newlist->next;    
                    j+=1;
                }
            }
        }
        if(i<k){    // 最后不足k个元素,将对应的有序部分追加到结果上
            ans->next = newlist;
        }else{
            ans->next = pre->next;    // 足够k个翻转,需要将最后一次翻转后的元素 追加到结果链表上来
            ans = end;
        }
        return head->next;
    }
};

结果:

Runtime: 24 ms, faster than 100.00% of C++ online submissions for Reverse Nodes in k-Group.

Memory Usage: 11 MB, less than 5.02% of C++ online submissions for Reverse Nodes in k-Group.

虽然以上解法,在leetcode提交中给到了100%的结果,但可见此解法逻辑之混乱,代码之冗余。分析原因主要还是对链表的操作不是很熟,导致各种胡拼乱凑,这里之所以将代码贴出来,主要是希望能够起到一个抛砖引玉出的作用。

Code2 & C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
     		ListNode dummy(-1);
	ListNode *pre = &dummy, *cur = head;
	dummy.next = head;
	int num = 0;
	while(cur){
		++num;
		cur = cur->next;
	}
	while(num>=k){
		cur = pre->next;
		for(int i=1;i<k;++i){
			ListNode *tmp = cur->next;
			cur->next = tmp->next;
			tmp->next = pre->next;
			pre->next = tmp;
		}
		pre = cur;
		num -= k;
	}
	return dummy.next;
    }
};

结果:

Runtime: 20 ms, faster than 100.00% of C++ online submissions for Reverse Nodes in k-Group.

Memory Usage: 10.3 MB, less than 39.00% of C++ online submissions for Reverse Nodes in k-Group.

很明显可以发现,第二种解法思路很清晰。另外还可以发现两种解法虽然时间不同,却给出了同样的成绩,可见leetcode的后台判定有些不稳定- 。-!!

Code2 & Python

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
        p = head
        num = 0
        while p!=None:
            num+=1
            p = p.next
        pre = ListNode(-1)
        pre.next = head
        ans = pre
        while num>=k:
            cur = pre.next
            for i in range(1,k):
                tmp = cur.next
                cur.next = tmp.next
                tmp.next = pre.next
                pre.next = tmp
            pre = cur
            num-=k
        return ans.next

结果:

Runtime: 56 ms, faster than 70.70% of Python3 online submissions for Reverse Nodes in k-Group.

Memory Usage: 14.2 MB, less than 5.33% of Python3 online submissions for Reverse Nodes in k-Group.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值