将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度
,空间复杂度
。
例如:
给出的链表为
,
,
返回
.
例如:
给出的链表为
返回
数据范围: 链表长度
,
,链表中每个节点的值满足
要求:时间复杂度
,空间复杂度
进阶:时间复杂度
,空间复杂度
import java.util.*; /* * public class ListNode { * int val; * ListNode next = null; * public ListNode(int val) { * this.val = val; * } * } */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param head ListNode类 * @param m int整型 * @param n int整型 * @return ListNode类 */ public ListNode reverseBetween (ListNode head, int m, int n) { // write code here //如果链表为空,直接返回空 if (head == null) { return null; } //如果 m == n,说明不需要反转,直接返回原链表 else if (m == n) { return head; } //创建一个虚拟头节点 pre,用于处理从头开始反转的情况(比如 m=1) //p1 是 pre 的指针,用来遍历找到第 m - 1 个节点的位置 else { ListNode pre = new ListNode(0), p1 = pre; pre.next = head; //将 p1 指到第 m - 1 个节点,此时: //p1.next 就是需要开始反转的第一个节点(即第 m 个节点) for (int i = 1; i < m; i++) { p1 = p1.next; } //p2 指向当前要反转的起始节点(即第 m 个节点) //temp 记录操作前的节点数据,后续用于连接后半段链表 ListNode p2 = p1.next, temp = p1.next; //使用“头插法”,把 p2 所在的节点依次插入到 p1 后面,从而实现局部反转 for (int j = m; j <= n; j++) { //node = p2.next: 保存下一个要反转的节点 ListNode node = p2.next; //p2.next = p1.next: 当前节点插入到 p1 后面 p2.next = p1.next; //p1.next = p2: 插入完成 p1.next = p2; //p2 = node: 继续处理下一个节点 p2 = node; } //将原来的第一个反转节点(temp)指向 p2,也就是反转后的剩余部分 temp.next = p2; //返回 pre.next,确保即使头节点被反转了也能正确返回新头节点 return pre.next; } } }
import java.util.*; /* * public class ListNode { * int val; * ListNode next = null; * public ListNode(int val) { * this.val = val; * } * } */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param head ListNode类 * @param m int整型 * @param n int整型 * @return ListNode类 */ public ListNode reverseBetween (ListNode head, int m, int n) { ListNode[] nodes = new ListNode[n+1]; List<ListNode> list = new ArrayList<>(); int loc=1; while(head != null) { if(loc<m) { nodes[loc] = head; } else if(loc>=m && loc<=n) { nodes[n-(loc-m)] = head; } else { list.add(head); } head = head.next; loc++; } head = new ListNode(-1); ListNode r = head; for(int i=1; i<=n; i++) { System.out.println(nodes[i].val); r.next = nodes[i]; r = r.next; } for(int i=0; i<list.size(); i++) { System.out.println(list.get(i).val); r.next = list.get(i); r = r.next; } r.next = null; return head.next; } }
public class Solution { public ListNode reverseBetween (ListNode head, int m, int n) { // write code here if (m == n) { return head; } ListNode temp = head; List<ListNode> cache = new ArrayList<>(n-m+1); int sign = 1; while(head!=null){ if(sign>=m&&sign<=n){ cache.add(head); } head= head.next; sign++; } int left = 0; int right = cache.size()-1; while(left<right){ ListNode leftNode = cache.get(left); ListNode rightNode = cache.get(right); int leftTemp = leftNode.val; leftNode.val = rightNode.val; rightNode.val = leftTemp; left++; right--; } return temp; } }
利用栈
public ListNode reverseBetween (ListNode head, int m, int n) { // write code here Stack stack = new Stack(); ListNode temp = new ListNode(0); ListNode temp1 = temp; int count = 1; while (head != null) { if (count >= m && count <= n) { stack.push(head); } else { if (stack.isEmpty()) { temp.next = head; temp = head; } else { while (!stack.isEmpty()) { ListNode pop = stack.pop(); temp.next = pop; temp = pop; } temp.next = head; temp = head; } } count++; head = head.next; } if (!stack.isEmpty()) { while (!stack.isEmpty()) { ListNode pop = stack.pop(); temp.next = pop; temp = pop; } temp.next = null; } return temp1.next; }
import java.util.*; /* * public class ListNode { * int val; * ListNode next = null; * public ListNode(int val) { * this.val = val; * } * } */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param head ListNode类 * @param m int整型 * @param n int整型 * @return ListNode类 */ public ListNode reverseBetween (ListNode head, int m, int n) { // write code here // 1.先定义两个指针start和end,分别指向前方的m位置和后方的n位置 ListNode start = null; ListNode end = null; // 2.记录start指针的上一个结点allPre,end指针的下一个结点allPost ListNode allPre = head; // 先把allPre指向head这个整个链表的起点,随着查找m可以往后移动head ListNode allPost = null; // 准备找到m和n位置对应的start和end,以及对应的allPre和allPost ListNode cur = head; for (int i = 1; cur != null; cur = cur.next, i++) { if (i == m) { start = cur; } if (i == n) { end = cur; allPost = end.next; break; } // 只有在i>1(让allPre落后一位)且i<m(还没找到start)时更新allPre if (i > 1 && i < m) { allPre = allPre.next; } } System.out.println("allPre: " + (allPre != null ? allPre.val : "null")); System.out.println("start: " + (start != null ? start.val : "null")); System.out.println("end: " + (end != null ? end.val : "null")); System.out.println("allPost: " + (allPost != null ? allPost.val : "null")); // 3.执行类似于上一题的方法,反转start和end之间的链表,返回反转后的起点newStart和终点newEnd ListNode newStart = end; ListNode newEnd = start; // 只有strat和end不指向同一个结点(反转区间>1)时,才有反转的必要 if (start != end) { ListNode newPre = start; ListNode newCur = start.next; ListNode newNext = newCur.next; // 此处不用管newPre的next指向何方,因为这个newPre就是newEnd,是数组反转后的结尾,下文会令其指向allPost while(newCur != allPost) { newNext = newCur.next; newCur.next = newPre; System.out.println("结点" + newCur.val + "的反转已完成"); newPre = newCur; newCur = newNext; } } // 4.令allPre指向newStart,令allPost指向newEnd // 注意allPre的边界判断!allPre可能与newEnd(start)重合! if (allPre == newEnd) { // 如果allPre 跟 newEnd(start) 是同一个结点(m=1的情况),说明start前面没有任何元素,这时可以直接移动head到链表区间反转后的起点,令head = newStart allPre = newStart; head = allPre; } else { // 否则,是正常情况,令allPre指向newStart,从newStart到newEnd是反转区间 allPre.next = newStart; } newEnd.next = allPost; System.out.println("newEnd结点" + newEnd.val + "的下一个结点allPost是" + (allPost != null ? allPost.val : "null")); System.out.println("allPre结点" + allPre.val + "的下一个结点newStart是" + (newStart != null ? newStart.val : "null")); System.out.println("head结点" + head.val); return head; } }
public ListNode reverseBetween (ListNode head, int m, int n) { // write code here ListNode pre=new ListNode(0) ,p1=pre; pre.next=head; for(int i=1;i<m;i++){ p1=p1.next; } ListNode p2=p1.next ,temp=p1.next; for(int i=m;i<=n;i++){ ListNode node=p2.next; p2.next=p1.next; p1.next=p2; p2=node; } temp.next=p2; return pre.next; }
public ListNode reverseBetween (ListNode head, int m, int n) { // write code here if (head == null || m >= n) { return head; } ListNode rootNode = new ListNode(0); rootNode.next = head; ListNode pre = null; ListNode mNode = null; ListNode nNode = null; ListNode mmNode = null; int k = 1; int j = 0; while(k <= n && head!= null){ if (k+1 == m){ mNode = head; mmNode = head.next; j++; }else if(k == m && j == 0){ mNode = rootNode; mmNode = head; } if (k == n){ nNode = head.next; } if (k >= m && k <= n){ ListNode temp = head.next; head.next = pre; pre = head; head = temp; }else{ head = head.next; } k++; } mNode.next = pre; mmNode.next = nNode; return rootNode.next; // 返回链表的头节点 }为解题而解题硬凑的,算法还是Java排第一的那个妙
import java.util.*; /* * public class ListNode { * int val; * ListNode next = null; * public ListNode(int val) { * this.val = val; * } * } */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param head ListNode类 * @param m int整型 * @param n int整型 * @return ListNode类 */ public ListNode reverseBetween (ListNode head, int m, int n) { // write code here ListNode tmp = head; ListNode pre, cur, preNode = null, tailNode = null; int i = 0; //范围包含头结点,则创建一个结点使得 next 域指向 head if (m == 1) { preNode = new ListNode(0); preNode.next = head; } //遍历链表找到起始节点 while (tmp != null) { //若范围不包含头节点,则记录范围两头相邻的节点preNode、tailNode if (i == m - 2) { preNode = tmp; } if (i == n) { tailNode = tmp; } tmp = tmp.next; i++; } pre = null; cur = preNode.next; //反转链表 while (cur != null) { if (cur == preNode.next) { pre = tailNode; } tmp = cur.next; cur.next = pre; pre = cur; cur = tmp; if (cur == tailNode) { preNode.next = pre; break; } } if (m == 1) { return preNode.next; } return head; } }
public class Solution {
/** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * *
@param head ListNode类
@param m int整型
@param n int整型
@return ListNode类
*/
public ListNode reverseBetween (ListNode head, int m, int n) {
// write code here ListNode root = new ListNode(-1); root.next = head; ListNode left = null; ListNode right = null; ListNode begin = root; ListNode end = root; for(int i=0;i<m;i++){ left = begin; begin = begin.next; } for(int i=0;i<n;i++){ end = end.next; right = end.next; } left.next = null; end.next = null; reverseNode(begin); left.next = end; begin.next = right; return root.next;
}
public ListNode reverseNode (ListNode head){
if(head == null) { return null; } ListNode pre = null; ListNode next = null; while(head != null) { next = head.next; head.next = pre; pre = head; head = next; } return pre;
}
}
import java.util.*; /* * public class ListNode { * int val; * ListNode next = null; * public ListNode(int val) { * this.val = val; * } * } */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param head ListNode类 * @param m int整型 * @param n int整型 * @return ListNode类 */ public ListNode reverseBetween (ListNode head, int m, int n) { ListNode pre=new ListNode(-1); pre.next=head; ListNode cp=head; ListNode cur=head; ListNode start=pre; int left=1; while(left<m){start=cp;cp=cp.next;cur=cur.next;left++;} while(left<n){cur=cur.next;left++;} ListNode last=cur.next; int s=m; while(s<=n){ ListNode next=cp.next; cp.next=last; last=cp; cp=next; s++; } start.next=cur; return pre.next; // write code here } }
public ListNode reverseBetween (ListNode head, int m, int n) { //此情况无需反转 if(m == n ) { return head; } //虚拟节点,防止从第一个节点就开始反转(m=1的情况) ListNode res = new ListNode(-1); res.next = head; //指针,指向反转节点的 前一个节点,用于连接 反转后的节点 ListNode perfix = res; ListNode p = head; //找到第一个反转的开始节点 while(p.next != null && m > 1) { p = p.next; perfix = perfix.next; m--; n--; } ListNode reversNode = null; //开始反转 while(p != null && n > 0) { ListNode tmp = p.next; p.next = reversNode; reversNode = p; p = tmp; n--; } //reversNode 就是反转后的节点 perfix.next = reversNode; ListNode s = reversNode; //指针s,找到反转后的链表 的最后一个节点 while (s.next != null) { s = s.next; } //将这个节点连接上p s.next = p; return res.next; }