• Leetcode 25:Reverse Nodes in k-Group


    1.题目描述

    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个元素,最后返回翻转后的链表。k是一个小于等于链表长度的整数,如果链表当中的节点数不是k的整数倍,那么除了可以翻转的那部分,剩余的不做处理。不允许改变节点的数值,只能对节点本身进行操作,同时要求常数级的空间开销。
    举例说明:
    给定一个链表:1->2->3->4->5
    当k=2时,2->1->4->3->5
    当k=3时,3->2->1->4->5

    2.解题思路

    这道题的难度是hard,但是解题思路很清晰:每次取出k个节点进行翻转,注意保持好链表的性质,最后少于k个的节点不做处理。那么它的难点在哪里? 就是你怎么使用常数级的空间开销来实现一个链表的反转,同时保持链表单向链接的性质!!此处是重点:在数据结构的单链表部分,单链表的插入有头插法和尾插法两种,这里就是利用头插法实现单链表的翻转。 何为头插法,请点击这里,看详细的解析。
    在处理链表问题的时候,一般我们会给链表加上头指针,注意和头结点区别。因为头指针在处理边界问题的时候比较方便,这道题目也用到这一点,同时需要一些指针来保存要翻转的部分链表开始和结束的位置。

    -1->1->2->3->4->5
     |           |
    pre         next
    
    -1->3->2->1->4->5
              |  |
             pre next
    

    3.代码实现

    1. 单独实现头插法
    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
         public ListNode reversek(ListNode pre,ListNode end) {
        	ListNode l1 = pre.next;//pre起到头指针的作用
        	ListNode l2 = l1.next;
        	while(l2 != end) {
        		//pre.next = l2.next;
        	    l1.next = l2.next;//取出l2
        		l2.next = pre.next;//把l2放在头结点的位置
        		pre.next = l2;//保持链表性质
        		l2 = l1.next;//更新l2位置
        		
        	}
        	return l1;
        }
         public ListNode reverseKGroup(ListNode head, int k) {   
        	if(head==null)
        		return null;
        	if(k==0||k==1||head.next==null)//特殊情况的判断
            	return head;
        	ListNode dum = new ListNode(-1);//java里不知道怎么叫,头指针?
        	dum.next = head;
        	ListNode pre = dum,cur = head;
        	int count=0;
        	while(cur!=null) {
           ListNode p = pre.next;
            count = k;
            while(count!=0 && p!=null){
                count--;
                p = p.next;
            }//每次while循环的步长是k
                if(count>0)
                    break;
                if(count==0){
                  pre = reversek( pre,p);//头插法处理
                  cur = pre.next;//下一次翻转开始位置
                }
        }
             return dum.next;
        }
    
    }
     
    
    1. 一个函数搞定
    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
    
         public ListNode reverseKGroup(ListNode head, int k) {   
        	if(head==null)
        		return null;
        	if(k==0||k==1||head.next==null)
            	return head;
        	ListNode dum = new ListNode(-1);
        	dum.next = head;
        	ListNode pre = dum,cur =head;
        	int count=0;
        	while(cur!=null){//遍历链表,获得长度
                count++;
                cur= cur.next;
            }
            System.out.println(count);
            while(count>=k){//头插法,注意是>=
                cur = pre.next;
                for(int i = 0;i<k-1;i++){//注意这里循环的次数是k-1次,是个坑
                    ListNode t = cur.next;
                    cur.next  = t.next;
                    t.next = pre.next;
                    pre.next = t;
                }
                pre = cur;
                count -=k;
            }
             return dum.next;
        }
    
    }
    
    1. 未通过代码,突发奇想使用Stack压栈和出栈的过程就完成了翻转,思路更简单,但是想想也不太可能当k很大的时候,肯定不符合条件,不通过的原因是超时,代码如下:
    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
    
         public ListNode reverseKGroup(ListNode head, int k) {   
        	if(head==null)
        		return null;
        	//if(k==0||k==1||head.next==null)
            //	return head;
        	ListNode dum = new ListNode(-1);
        	dum.next = head;
        	ListNode pre = dum,cur =pre;
        	int count=0;
        	Stack<ListNode> tmp = new Stack<ListNode>();
             while(cur!=null){
                count =k;
                 while(count!=0 && cur != null){
                     cur=cur.next;
                     count--;
                     tmp.push(cur);
                 }
                 if(count>0)
                     break;
                 if(count==0){
                     while(!tmp.empty()){
                         pre.next = tmp.pop();
                         pre = pre.next;
                     }
                 }
                 cur = pre;
             }
            
             return dum.next;
        }
    
    }
    

  • 相关阅读:
    一个貌似比较吊的递归转换为loop--总算成功了.
    为何反转迭代顺序就不会栈溢出了?
    将树形递归转换为loop
    递归和迭代之间的转换简单例子
    非线性递归函数转化为迭代函数举例
    将尾递归函数转换为迭代函数的利器
    转:LINUX/UNIX下的回车换行与WINDOWS下的区别
    property干嘛的
    eval和列表解析的一处陷阱
    剑指offer——16二进制中1的个数
  • 原文地址:https://www.cnblogs.com/chailinbo/p/7583671.html
Copyright © 2020-2023  润新知