1. 问题描述
问题主要就是将链表从m,n翻转其中的节点,包含m和n这个节点
1<=m<=n<=head.length
1->2->3->4->5->NULL m=2,n=4 即反转m与n之间的链表
1->4->3->2->5->NULL
2. 思路
2.1 思路1
思路1的话主要是找到m,然后遍历找到n,然后翻转m-n之间的节点,然后将前后拼接起来即可
public ListNode reverseBetweenII(ListNode head, int m, int n) { if (head == null || head.next == null) return head; ListNode dummyNode = new ListNode(0); dummyNode.next = head; int cnt = 0; ListNode pre = dummyNode;// 设置虚拟节点 ListNode cur = pre.next;// 设置头节点 while (cur != null) { cnt += 1; if (cnt == m) {// 找到第一个节点 ListNode t = cur;// 记录下来拼接尾节点的前一个节点 while (cnt != n) { cnt += 1; cur = cur.next; } // temp作为尾节点 ListNode temp = cur.next; cur.next = null;// 切断联系 ListNode node1 = pre.next;// 记录需要翻转的部分 pre.next = null;// 切断联系 pre.next = reverseNode(node1);// 翻转,然后头节点拼接上 t.next = temp;// 尾节点拼接,返回即可 return dummyNode.next; } cur = cur.next; pre = pre.next; } return null; } private ListNode reverseNode(ListNode head) { if (head == null) return null; if (head.next == null) return head; ListNode p = reverseNode(head.next);// 一直遍历找最后一个 head.next.next = head;// 通过修改空间中的指针指向,这里实质修改了节点与p的关系 head.next = null;// 切点head节点的联系 return p; }
2.2 思路2
思路2的话主要是通过递归的方法来,如果是从m=1开始翻转,则直接返回翻转后的。这里的翻转是记录尾节点即tailNode,然后再中途修改head指针与node指针之间的关系,从而实现链表翻转。如果是画图的话,可以看到,所有的节点其实就是从节点的上一个节点插入到tailNode前面,从而维持相对的关系。
ListNode tailNode = null; public ListNode reverseBetween(ListNode head, int m, int n) { if (m == 1) { // 如果是第一个节点开始,全都翻转 return reverseN(head, n); } // 因为翻转的是相对大小位置,所以m-1,则n-1,需要对应变化才奏效 head.next = reverseBetween(head.next, m - 1, n - 1); return head; } private ListNode reverseN(ListNode head, int n) { // 获取到尾节点,就是为了待会连接的问题 if (n == 1) { tailNode = head.next;// 保留尾部节点 return head; } // 递归向后走 ListNode node = reverseN(head.next, n - 1); // 改变节点与node的指向 head.next.next = head; // 实质就是往靠近tailNode的位置插入 head.next = tailNode; // 返回node return node; }
3. 小结
这道题之前也做过,但是许久不做又生疏了,但是如果做也可以做出来。只是链表的转向真的比较有趣。如果不熟悉最好打断点,然后画图,还是比较简单的。
Keep thinking, keep coding! 加油
2020-08-25写于深圳南山