NC21:链表内指定区间反转
链表内指定区间反转
http://www.nowcoder.com/practice/b58434e200a648c589ca2063f1faf58c
解法1:双指针法
pre先走m-1步到达位置m的前驱节点,pre不动,然后令cur等于pre->next也就是位置m的起始节点(不变),将[m+1,n]这段链表由前至后的插入到位置m的前面,也就是pre的后面
即:我们每次循环就是将cur的next节点插入到pre的后面,这样插了n-m次后,就完成反转了
public ListNode reverseBetween (ListNode head, int m, int n) { // write code here // 设置哑节点的好处: //在m=1时,我们也有前驱节点,也可以将cur的next节点依次插入到pre的后面 ListNode dummy=new ListNode(-1); dummy.next=head; ListNode pre=dummy; // 找到m的前驱节点 for(int i=1;i<m;i++){ pre=pre.next; } ListNode cur=pre.next; // 每次循环将tmp节点插入到pre的后面 for(int i=m;i<n;i++){ ListNode tmp=cur.next; cur.next=tmp.next;// cur将tmp节点后面的链表连接起来 tmp.next=pre.next;// 将tmp插入到pre后面 pre.next=tmp; } //例如0->1->2->3->4->5->6->7->8->9->10,翻转2--8; // 第1次i=2:0->1->3->2->4->5->6->7->8->9->10 // 第2次i=3:0->1->4->3->2->5->6->7->8->9->10 // 第3次i=4:0->1->5->4->3->2->6->7->8->9->10 // 第4次i=5:0->1->6->5->4->3->2->7->8->9->10 // 第5次i=6:0->1->7->6->5->4->3->2->8->9->10 // 第6次i=7:0->1->8->7->6->5->4->3->2->9->10 return dummy.next; }
解法2:暴力求解
public ListNode reverseBetween(ListNode head, int m, int n) { if(head == null) { return head; } List<Integer> list = new ArrayList<>(); ListNode cur = head; while (cur != null) { list.add(cur.val); //所有元素放入集合 cur = cur.next; } int i = m - 1; //注意索引要减一,因为集合从0开始 int j = n - 1; while (i < j) { //交换m到n的元素 int temp = list.get(i); list.set(i, list.get(j)); list.set(j, temp); i++; j--; } ListNode dumy = new ListNode(0); ListNode res = dumy; for (int k = 0; k < list.size(); k++) { dumy.next = new ListNode(list.get(k)); //重新串节点 dumy = dumy.next; } return res.next; } }
名企高频面试算法题解 文章被收录于专栏
牛客题霸 - 程序员面试高频题 - 题解