Reverse a linked list from position m to n. Do it in-place and in one-pass.
For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,
return 1->4->3->2->5->NULL.
Note:
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.
解法1:Two pointers, One Pass O(N)
题目要求只能走一遍,所以考虑用双指针。同时需要考虑到的是,等reverse结束,我们的head是不确定的,在这种情况下我们考虑使用dummy node,将dummy node指向head,最后不管其中怎么变化,我们一定是返回dummy.next
假设我们已经知道从node m 到node n需要reverse,那么reverse之后由于要并入原来的list,我们需要知道子list的head之前的那个node,以及子list的尾巴之后的那个node, 比如:
1->2->3->4->5, if m = 2, n = 4
那么我们需要记录指针位置1和指针位置5,当把2->3->4翻转过后把新的head和tail指向这两个节点就可以了。
实现上维护two pointers和一个计数器,当right pointer移动到子list的head的时候,left pointer就自然而然的指向了前面的那个node,把子list的head记录为newtail,因为当reverse之后他会变成tail。
然后开始reverse的过程,同时变更计数器,直到计数器等于n的值为止。这个时候我们就得到了新的head,记录下一个值便是我们要将newtail指向的位置。最后返回dummy.next
C++
Java
解法2:Two pointers, One Pass O(N)
解法1的思想比较直观,不过写起来比较繁琐。从discuss上看来的这个解法比较简洁。要注意的是其中有把一个子list反转的template需要记一下,很有用。
对于上面这个list,要反转A到C,那么设start为A,then为B两个指针。
prev不移动而移动start和then,每一次把start向后移动一位,并且把then指向的node接到prev之后就可以达到效果。
代码是
完整的代码就简洁多了。
Java