LeetCode第25题,每K个节点一组进行翻转,剩下不足K个的保留原状.java
将链表分红三部分,已翻转,待翻转,未翻转三部分:node
首先,用一个指针t表示要插入的位置的前驱,一边把head移动k遍,一边插入在t后面(下图假设k=3):git
int i=0; for(;i<k && head != null;++i) { temp = head.next; head.next = t.next; t.next = head; head = temp; }
直接插在t的后面,一轮循环以后,移动t与head.github
t的新位置为未插入head以前的head的位置,所以在插入以前把head的位置保存下来,直接使t移动到该位置,head的位置为天然移动到的位置,不需改变。算法
ListNode nextTPosition = head; ListNode temp; int i=0; for(;i<k && head != null;++i) { temp = head.next; head.next = t.next; t.next = head; head = temp; } if(i == k) t = nextTPosition;
接着再翻转,到达7后,7不须要翻转,由于剩下的节点数不足:ide
这时就须要i发挥做用了,i表示已翻转的节点的值,由于只是一次遍历,每遍历k次便翻转k次,若i小于k,因为已经翻转了剩下的i个节点,所以须要再将这剩下的i个节点翻转一次:优化
if(i == k) t = nextTPosition; else { for(head = t.next,t.next=null;head!=null;) { temp = head.next; head.next = t.next; t.next = head; head = temp; } break; }
对剩下的i个节点再次翻转时,不须要修改t的位置,使head指向t.next,再把t.next置为null,由于此时t为3d
4->7
若不把t.next置为null,在指针
head.next = t.next
这一步会使head.next指向错误的t.next,致使会在最后一个节点不断循环。
翻转最后的i个节点后,跳出循环,返回结果。code
递归的话思路也相似,遍历k次,翻转k个,若还有须要翻转的节点,递归翻转,若没有,翻转剩下的i个节点。
if(i == k) t.next = reverse(head,k);
大部分代码与循环相同就不贴了,最大的不一样是这里,这里的t为原来未遍历前的head,由于改为递归后,不须要使用t做为移动的指针指示插入的位置,t.next就至关于翻转后的最后一个节点,把递归的结果插入到这个节点的后面。
由于题目规定只能使用常数的额外空间,所以应该只有这两种方法了,可是,若是容许使用额外的空间,可使用栈优化直接翻转的算法。
由于出栈的次序正是翻转的顺序,每遍历k个节点就压栈k个节点,若剩余不足k个节点,把head连上dummy,若还有多余的节点或者恰好遍历完,把出栈的节点依次连上主链。
while(true) { Stack<ListNode> s = new Stack<>(); ListNode temp = head; int i=0; for(;i<k && head != null;++i) { s.add(new ListNode(head.val)); head = head.next; } if(i == k) { for(i=0;i<k;++i) { t.next = s.pop(); t = t.next; } } else if(head == null) { t.next = temp; break; } }
其中for循环为遍历压栈,i==k判断是否翻转链表。