1、反转链表
题目描述:
给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
数据范围: 0\leq n\leq10000≤n≤1000
要求:空间复杂度 O(1)O(1) ,时间复杂度 O(n)O(n) 。
如当输入链表{1,2,3}时,
经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。
以上转换过程如下图所示:
示例:
思路:
-
用两个指针指示前置节点与当前节点
-
初始化两个节点
-
不断移动两个指针的同时改变当前节点的方向,直到到达最后一个节点
代码:
/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Solution { public ListNode ReverseList(ListNode head) { //记录前置节点和当前节点位置 ListNode pre = null; ListNode cur = head; //不断移动cur节点,向后遍历,同时更改nex //当cur为空时,遍历完成 while(cur != null){ //将cur下一个节点存起来 ListNode temp = cur.next; //更改方向 cur.next = pre; //pre cur都后移 pre = cur; cur = temp; } return pre; } }
2、链表内指定区间反转
题目描述:
将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)。 例如: 给出的链表为 1\to 2 \to 3 \to 4 \to 5 \to NULL1→2→3→4→5→NUL**L, m=2,n=4m=2,n=4, 返回 1\to 4\to 3\to 2\to 5\to NULL1→4→3→2→5→NUL**L.
数据范围: 链表长度 0 < size \le 10000<siz**e≤1000,0 < m \le n \le size0<m≤n≤siz**e,链表中每个节点的值满足 |val| \le 1000∣val∣≤1000
要求:时间复杂度 O(n)O(n) ,空间复杂度 O(n)O(n)
进阶:时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)
示例:
思路:
-
new一个空节点指示链表,因为只翻转一段区间,得找到链表头。
-
设置两个节点一个指向当前节点,一个指向当前节点的前置节点。
-
初始化这两个节点,让它们指向第m个节点以及第m个节点的前一个节点,
-
然后向后翻转n-m次就完成了m到之间的节点的翻转。
import java.util.*; /* * public class ListNode { * int val; * ListNode next = null; * } */ 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||head.next==null){ return head; } if((n-m)<1){ return head; } //初始化一个空节点 ListNode tmpHead = new ListNode(0); tmpHead.next = head; //记录当前节点位置和前置节点位置 ListNode cur = head; ListNode pre = tmpHead; for(int i=1; i<m; i++){ cur = cur.next; pre = pre.next; } for(int i=0; i<n-m; i++){ //将cur下一个节点存起来 ListNode temp = cur.next; //cur后移 cur.next = cur.next.next; //翻转 temp.next = pre.next; //pre后移 pre.next = temp; } return tmpHead.next; } }
3、链表中的节点每个k个一组翻转
题目描述:
将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表 如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样 你不能更改节点中的值,只能更改节点本身。
数据范围: \ 0 \le n \le 2000 0≤n≤2000 , 1 \le k \le 20001≤k≤2000 ,链表中每个元素都满足 0 \le val \le 10000≤val≤1000 要求空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
例如:
给定的链表是 1\to2\to3\to4\to51→2→3→4→5
对于 k = 2k=2 , 你应该返回 2\to 1\to 4\to 3\to 52→1→4→3→5
对于 k = 3k=3 , 你应该返回 3\to2 \to1 \to 4\to 53→2→1→4→5
示例:
思路:
-
new一个空节点指示链表
-
设置三个节点cur,pre,temp
-
计算链表长度
-
遍历链表,k个k个交换,每一组交换完后要更新pre和cur
代码:
import java.util.*; /* * public class ListNode { * int val; * ListNode next = null; * } */ public class Solution { /** * * @param head ListNode类 * @param k int整型 * @return ListNode类 */ public ListNode reverseKGroup (ListNode head, int k) { // write code here //严谨性判断 if(head == null || head.next == null || k < 2) return head; //初始化一个空节点 ListNode tmpHead = new ListNode(0); tmpHead.next = head; //记录前置节点位置,当前节点位置,和一个temp ListNode pre = tmpHead, cur = head, temp; int len = 0; //求链表长度 while (head != null) { len ++ ; head = head.next; } //外层循环决定有多少组 //内层循环翻转 for (int i = 0; i < len / k; i ++ ) { for (int j = 1; j < k; j ++ ) { //下一个节点 temp = cur.next; //cur后移 cur.next = temp.next; //翻转 temp.next = pre.next; //pre后移 pre.next = temp; } //交换完之后,更新cur,pre pre = cur; cur = cur.next; } return tmpHead.next; } }
4、合并两个排序的链表
题目描述:
输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
数据范围: 0 \le n \le 10000≤n≤1000,-1000 \le 节点值 \le 1000−1000≤节点值≤1000 要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
如输入{1,3,5},{2,4,6}时,合并后的链表为{1,2,3,4,5,6},所以对应的输出为{1,2,3,4,5,6},转换过程如下图所示:
或输入{-1,2,4},{1,3,4}时,合并后的链表为{-1,1,2,3,4,4},所以对应的输出为{-1,1,2,3,4,4},转换过程如下图所示:
示例:
思路:
-
设置一个ListNode记录结果
-
设置一个指针pre指示待插入节点的前一个节点(即当前节点)
-
这是两个指针pre1,pre2指示list1,list2
-
选择两个链表中较小值作为pre,然后后移
代码:
/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Solution { public ListNode Merge(ListNode list1,ListNode list2) { if(list1==null) return list2; if(list2==null) return list1; //head记录结果,初始化为list1,list2较小值 ListNode head = list1.val < list2.val ? list1 : list2; //pre指示下一个节点的前一个节点(即当前节点) ListNode pre = head; //cur1指示下一个节点(来自于list1或list2) ListNode cur1 = head.next; //cur2指示下一个节点(来自另一个链表) ListNode cur2 = (head == list1) ? list2 : list1; while (cur1 != null && cur2 != null) { if (cur1.val < cur2.val) { pre.next = cur1; cur1 = cur1.next; } else { pre.next = cur2; cur2 = cur2.next; } pre = pre.next; } pre.next = cur1 == null ? cur2 : cur1; return head; } }
5、合并k个已排序的链表
题目描述:
合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。
数据范围:节点总数满足 0 ≤n≤10^5, 链表个数满足 1≤k≤10^5 ,每个链表的长度满足 1≤len≤200 ,每个节点的值满足 |val| <= 1000∣val∣&