情绪(稳定性)不稳定:快些选堆java
排序名称 | 时间复杂度 | 空间复杂度 | 稳定性 | 备注 |
---|---|---|---|---|
选择排序 | O(n^2) | O(1) | 不稳定 | 运行时间和输入无关;数据移动是最少的 |
插入排序 | O(n^2),彻底有序变成O(n) | O(1) | 稳定 | 排序时间取决于初始值(使用交换方式) |
冒泡排序 | O(n^2),彻底有序变成O(n) | O(1) | 稳定 | |
归并排序 | O(nlogn),彻底有序变成O(n) | O(n) | 稳定 | 求解逆序对、小和、染色等问题 |
快速排序 | O(nlogn),含有相同元素数组,三路快排O(n) | O(1) | 不稳定 | 求解topK等问题 |
堆排序 | O(nlogn) | O(1) | 不稳定 | 实现优先队列 |
希尔排序 | O(nlogn)-O(n^2) | O(1) | 不稳定 | 分组思想 |
public class SelectionSort { private SelectionSort() { } // 默写版 public static void selectionSort(int[] arr) { for (int i = 0; i < arr.length; i++) { int minIndex = i; for (int j = i + 1; j < arr.length; j++) { minIndex = arr[minIndex] < arr[j] ? minIndex : j; } swap(arr, i, minIndex); } } private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } // 选择排序1:从前到后选最小 public static <E extends Comparable<E>> void selectionSort(E[] arr) { for (int i = 0; i < arr.length; i++) { int minIndex = i; for (int j = i + 1; j < arr.length; j++) { // 循环不变量:minIndex永远指向最小的元素 minIndex = arr[minIndex].compareTo(arr[j]) < 0 ? minIndex : j; } swap(arr, i, minIndex); } } // 选择排序2从后到前选最大 public static <E extends Comparable<E>> void selectionSort1(E[] arr) { for (int i = arr.length - 1; i >= 0; i--) { int maxIndex = i; for (int j = i - 1; j >= 0; j--) { maxIndex = arr[j].compareTo(arr[maxIndex]) > 0 ? j : maxIndex; } swap(arr, i, maxIndex); } } private static <E> void swap(E[] arr, int i, int j) { E temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }
public class InsertionSort { private InsertionSort() { } // 默写版 private static void insertSort(int[] arr) { for (int i = 0; i < arr.length; i++) { int temp = arr[i]; int j; // 从后往前插 for (j = i; j - 1 >= 0 && temp < arr[j - 1]; j--) { arr[j] = arr[j - 1]; } arr[j] = temp; } } // 插入排序1:取出元素插入,后面希尔排序会用到这种方式 public static <E extends Comparable<E>> void insertSort1(E[] data) { // 外层循环:遍历每一个数组元素,i左边已经排好序,右边待排序 for (int i = 0; i < data.length; i++) { // 取出当前遍历第一个元素,将它插入到前面已经排好序的数组中,合适的位置 E temp = data[i]; // 内层循环:遍历左边已经排好序的数组 int j; // &&右边的条件不能下放!由于j--会对一个位移 for (j = i; j - 1 >= 0 && temp.compareTo(data[j - 1]) < 0; j--) { data[j] = data[j - 1]; } // 内层发生移动,空出的j位置赋值给temp // 内层没有发生移动,temp原地赋值给本身 data[j] = temp; } } // 插入排序2:使用交换,性能没有上面好 public static <E extends Comparable<E>> void insertSort2(E[] arr) { for (int i = 1; i < arr.length; i++) { for (int j = i - 1; j >= 0 && arr[j].compareTo(arr[j + 1]) > 0; j++) { swap(arr, j, j + 1); } } } private static <E> void swap(E[] arr, int j, int i) { E t = arr[i]; arr[i] = arr[j]; arr[j] = t; } }
public class Solution { public ListNode insertionSortList(ListNode head) { if (head == null) { return null; } // 初始化三个指针:dummyNode防止cur插入到head位置 ListNode dummyNode = new ListNode(0); dummyNode.next = head; ListNode lastSorted = head; ListNode cur = head.next; // cur指针遍历,循环结束条件是cur==null while (cur != null) { // lastSorted后移条件 if (lastSorted.val <= cur.val) { lastSorted = lastSorted.next; } else { // 不然,从头遍历链表找最后<=cur.val的节点 ListNode pre = dummyNode; while (pre.next.val <= cur.val) { pre = pre.next; } // 将cur插入到pre后一位,改变三者指向 lastSorted.next = cur.next; cur.next = pre.next; pre.next = cur; } // cur为待插入结点=last后一位 cur = lastSorted.next; } // 返回dummyNode下一位 return dummyNode.next; } }
public class BubbleSort { private BubbleSort() { } // 默写版 private static void bubbleSort(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { boolean isSwap = false; for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { swap1(arr, j, j + 1); isSwap = true; } } if (!isSwap) { break; } } } // 不使用额外空间,不考虑数字越界的交换 private static void swap1(int[] arr, int i, int j) { arr[j] = arr[i] + arr[j]; arr[i] = arr[j] - arr[i]; arr[j] = arr[j] - arr[i]; } // 冒泡排序常规写法:从后往前比较,这种写法比较好记 public static <E extends Comparable<E>> void bubbleSort0(E[] arr) { // 只须要n-1层外部循环 for (int i = arr.length - 1; i > 0; i--) { for (int j = 0; j < i; j++) { if (arr[j].compareTo(arr[j + 1]) > 0) { swap(arr, j, j + 1); } } } } // 冒泡排序1:优化设置交换标志位 public static <E extends Comparable<E>> void bubbleSort1(E[] arr) { // 外层实现比较次数:n-1次 for (int i = 0; i < arr.length - 1; i++) { // 优化:设置交换标志位 boolean isSwap = false; // 内层实现相邻元素比较:每趟只比较j和j+1的元素 for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j].compareTo(arr[j + 1]) > 0) { swap(arr, j, j + 1); isSwap = true; } } // 内层没有发生交换,说明前面已经都排好序了,就不用再次比较 if (!isSwap) { break; } } } // 冒泡排序2:优化设置最后交换位置,取消掉i++ public static <E extends Comparable<E>> void bubbleSort2(E[] arr) { for (int i = 0; i < arr.length - 1; ) { int swapNextIndex = 0; for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j].compareTo(arr[j + 1]) > 0) { swap(arr, j, j + 1); // 最后交换位置确定是靠后的j+1 swapNextIndex = j + 1; } } i = arr.length - swapNextIndex; } } private static <E> void swap(E[] arr, int i, int j) { E temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }
希尔排序是对插入排序的一种改进尝试,每次基于必定间隔的的两数进行排序,直到间隔为1再进行插入排序,此时几乎有序插入排序效率变高node
public class ShellSort { private ShellSort() { } /** * 希尔排序:对插入排序一种优化,又叫缩小增量排序,每次将数组一个元素与相同增量区间比较排序,直到增量为1 */ // 希尔排序1:利用插入排序更改 public static <E extends Comparable<E>> void shellSort1(E[] arr) { // 希尔的步长 int step = arr.length / 2; while (step >= 1) { // 插入排序 insertSort(arr, step); step = step / 2; } } private static <E extends Comparable<E>> void insertSort(E[] arr, int step) { for (int i = step; i < arr.length; i++) { E t = arr[i]; int j; for (j = i; j - step >= 0 && t.compareTo(arr[j - step]) < 0; j -= step) { arr[j] = arr[j - step]; } arr[j] = t; } } // 希尔排序2:三重循环 public static <E extends Comparable<E>> void shellSort2(E[] arr) { // 希尔的步长 int step = arr.length / 2; while (step >= 1) { // start是每一个子数组的起始位置 for (int start = 0; start < step; start++) { // 如下是使用插入排序 // 对每一个子数组进行插入排序:data[start+step,start+2h...data.length-1] for (int i = start + step; i < arr.length; i += step) { E temp = arr[i]; int j; // 前一个元素是j-step for (j = i; j - step >= 0 && temp.compareTo(arr[j - step]) < 0; j -= step) { arr[j] = arr[j - step]; } arr[j] = temp; } } step = step / 2; } } // 希尔排序3:修改步长序列 public static <E extends Comparable<E>> void shellSort3(E[] arr) { // 希尔的步长 int step = 1; while (step < arr.length) { step = step * 3 + 1; } while (step >= 1) { // 对每一个子数组进行插入排序:data[start+h,start+2h...data.length-1] for (int i = step; i < arr.length; i++) { E temp = arr[i]; int j; // 前一个元素是j-step for (j = i; j - step >= 0 && temp.compareTo(arr[j - step]) < 0; j -= step) { arr[j] = arr[j - step]; } arr[j] = temp; } step = step / 3; } } }
public class Solution { // 排序法 public String[] findRelativeRanks1(int[] score) { String[] result = new String[score.length]; // 复制原数组到排序数组 int[] sorted = new int[score.length]; System.arraycopy(score, 0, sorted, 0, score.length); Arrays.sort(sorted); for (int i = 0; i < score.length; i++) { int index = score.length - Arrays.binarySearch(sorted, score[i]); switch (index) { case 1: result[i] = "Gold Medal"; break; case 2: result[i] = "Silver Medal"; break; case 3: result[i] = "Bronze Medal"; break; default: result[i] = String.valueOf(index); } } return result; } // 计数排序法 public String[] findRelativeRanks2(int[] score) { String[] result = new String[score.length]; int max = Integer.MIN_VALUE; for (int num : score) { max = Math.max(max, num); } int[] array = new int[max + 1]; // 初始化arr数组,下标为score的值,arr[i]为该元素的排名 for (int i = 0; i < score.length; i++) { array[score[i]] = i + 1; } int rank = 1; for (int i = array.length - 1; i >= 0; i--) { if (array[i] != 0) { switch (rank) { case 1: result[array[i] - 1] = "Gold Medal"; break; case 2: result[array[i] - 1] = "Silver Medal"; break; case 3: result[array[i] - 1] = "Bronze Medal"; break; default: result[array[i] - 1] = String.valueOf(rank); } rank++; } } return result; } }
第一种版本是进行优化后的,便于对理解数组中的逆序对问题!算法
public class MergeSort { private MergeSort() { } public static <E extends Comparable<E>> void mergerSort(E[] arr) { // 优化:只生成一次辅助数组,使得merge中没有偏移量的操做了 // Arrays.copyOf(目标数组,开区间) E[] temp = Arrays.copyOf(arr, arr.length); mergerSort(arr, 0, arr.length - 1, temp); } private static <E extends Comparable<E>> void mergerSort(E[] arr, int l, int r, E[] temp) { // 优化2:指定长度内,可以使用直接插入排序优化,但这种优化效果不明显,因此这里放弃使用 if (l >= r) { return; } // 先递归分解 int mid = l + (r - l) / 2; mergerSort(arr, l, mid, temp); mergerSort(arr, mid + 1, r, temp); // 优化1:[l,mid]已经排序好,[mid+1...]后的位置 if (arr[mid].compareTo(arr[mid + 1]) > 0) { merge(arr, l, mid, r, temp); } } private static <E extends Comparable<E>> void merge(E[] arr, int l, int mid, int r, E[] temp) { // System.arraycopy(复制数组,复制数组起始位置,目标数组,目标数组起始位置,复制数组长度开区间) System.arraycopy(arr, l, temp, l, r - l + 1); // p遍历temp[l,mid];q遍历temp[mid+1,r] int p = l, q = mid + 1; // i遍历arr[l,r] for (int i = l; i <= r; i++) { if (p > mid) { arr[i] = temp[q++]; } else if (q > r) { arr[i] = temp[p++]; } else if (temp[p].compareTo(temp[q]) <= 0) { arr[i] = temp[p++]; } else { arr[i] = temp[q++]; } } } }
第二版是左程元上课时教的,我的认为是最容易理解和背诵的版本,但不利于书写数组逆序对问题shell
public class MergeSort1 { private MergeSort1() { } // 左神归并排序写法 public static void mergeSort(int[] arr) { if (arr.length < 2) { return; } mergeSort(arr, 0, arr.length - 1); } public static void mergeSort(int[] arr, int l, int r) { if (l == r) { return; } int mid = l + ((r - l) >> 1); mergeSort(arr, l, mid); mergeSort(arr, mid + 1, r); merge(arr, l, mid, r); } public static void merge(int[] arr, int l, int m, int r) { int[] temp = new int[r - l + 1]; int i = 0; int p1 = l; int p2 = m + 1; while (p1 <= m && p2 <= r) { temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++]; } while (p1 <= m) { temp[i++] = arr[p1++]; } while (p2 <= r) { temp[i++] = arr[p2++]; } for (i = 0; i < temp.length; i++) { arr[l + i] = temp[i]; } } private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }
很是高频的一道题数组
public class Solution { /** * 合并两个有序数组,num1长度大于m+n,m是num1长度,n是nums2长度 */ // 方法一:逆向双指针,不使用额外数组 public void merge(int[] nums1, int m, int[] nums2, int n) { // 初始化为各自-1的位置 int p1 = m - 1, p2 = n - 1, tail = m + n - 1; // temp存较大的数,从后往前放 int temp; while (p1 >= 0 || p2 >= 0) { // temp获取较大值 if (p1 == -1) { temp = nums2[p2--]; } else if (p2 == -1) { temp = nums1[p1--]; } else if (nums1[p1] < nums2[p2]) { temp = nums2[p2--]; } else { temp = nums1[p1--]; } // 利用尾指针存放temp nums1[tail--] = temp; } } // 方法二:正向双指针,须要使用额外数组 public void merge1(int[] nums1, int m, int[] nums2, int n) { // 初始化从0开始 int p1 = 0, p2 = 0; // 辅助变量存比较后的值 int temp; int[] help = new int[m + n]; while (p1 < m || p2 < n) { if (p1 == m) { temp = nums2[p2++]; } else if (p2 == n) { temp = nums1[p1++]; } else if (nums1[p1] < nums2[p2]) { temp = nums1[p1++]; } else { temp = nums2[p2++]; } // 辅助数组放下temp help[p1 + p2 - 1] = temp; } // 从help数组的0位置开始复制m+n个元素到nums1数组中,nums1数组从0位置开始接受 System.arraycopy(help, 0, nums1, 0, m + n); } }
public class Solution { public ListNode mergeTwoLists(ListNode l1, ListNode l2) { // dummyNode便于返回头结点 ListNode dummyNode = new ListNode(0); // cur初始化指向dummyNode ListNode cur = dummyNode; while (l1 != null && l2 != null) { if (l1.val < l2.val) { cur.next = l1; l1 = l1.next; } else { cur.next = l2; l2 = l2.next; } // 每次循环,cur后移 cur = cur.next; } cur.next = l1 != null ? l1 : l2; return dummyNode.next; } }
这道题很是高频,而且对于理解归并排序的归并操做有很大帮助,建议dubug多看几回less
public class Solution { private int res; // 归并排序法,若是左边大,那么左边未归并的部分就是造成逆序对的个数 public int reversePairs(int[] nums) { int[] temp = new int[nums.length]; res = 0; sort(nums, 0, nums.length - 1, temp); return res; } private void sort(int[] arr, int l, int r, int[] temp) { if (l >= r) { return; } int mid = l + (r - l) / 2; sort(arr, l, mid, temp); sort(arr, mid + 1, r, temp); // >保证了,若是j位置小于i位置的,左边未排序中的确定是逆序对 if (arr[mid] > arr[mid + 1]) { merge(arr, l, mid, r, temp); } } private void merge(int[] arr, int l, int mid, int r, int[] temp) { System.arraycopy(arr, l, temp, l, r - l + 1); int i = l, j = mid + 1; // 每轮循环为 arr[k] 赋值 for (int k = l; k <= r; k++) { if (i > mid) { arr[k] = temp[j++]; } else if (j > r) { arr[k] = temp[i++]; } else if (temp[i] <= temp[j]) { arr[k] = temp[i++]; } else { // 判断逆序对条件:temp[i]>temp[j] res += mid - i + 1; arr[k] = temp[j++]; } } } }
public class QuickSort { private QuickSort() { } // 单路快排默写版 public static void quickSort(int[] arr) { if (arr == null || arr.length < 2) { return; } Random random = new Random(); quickSort(arr, 0, arr.length - 1, random); } private static void quickSort(int[] arr, int l, int r, Random random) { if (l >= r) { return; } int p = partition(arr, l, r, random); quickSort(arr, l, p - 1, random); quickSort(arr, p + 1, r, random); } private static int partition(int[] arr, int l, int r, Random random) { swap(arr, l, l + random.nextInt(r - l + 1)); int less = l; for (int i = l + 1; i <= r; i++) { if (arr[i] < arr[l]) { swap(arr, i, ++less); } } swap(arr, l, less); return less; } public static <E extends Comparable<E>> void quickSort1(E[] arr) { Random random = new Random(); quickSort1(arr, 0, arr.length - 1, random); } private static <E extends Comparable<E>> void quickSort1(E[] arr, int l, int r, Random random) { // 不单单是递归结束条件,更是上轮l和r保证左小右大的条件 if (l >= r) return; // 将数组分区,随机得到一个基数,小于基数放左边,大于基数放右边,返回基数最终位置下标 int p = partition1(arr, l, r, random); // 对上一轮基数最终位置的左边,递归排序 quickSort1(arr, l, p - 1, random); // 对上一轮基数最终位置的右边,递归排序 quickSort1(arr, p + 1, r, random); } // partition:数组分区,随机得到一个基数,小于基数放左边,大于基数放右边,返回基数最终位置下标 private static <E extends Comparable<E>> int partition1(E[] arr, int l, int r, Random random) { // 随机交换l和p位置上的数,解决数组有序问题 int p = l + random.nextInt(r - l + 1); swap1(arr, l, p); // j初始化l int j = l; // 遍历l后续数组元素,j指向<arr[l]的最后一个数, for (int i = l + 1; i <= r; i++) { if (arr[i].compareTo(arr[l]) < 0) { j++; swap1(arr, i, j); } } // 循环跳出,交换基数与小于基数最后一个数 swap1(arr, l, j); // 因为上一步交换,此时arr[j]就是基数最终位置,返回j return j; } private static <E> void swap1(E[] arr, int i, int j) { E t = arr[i]; arr[i] = arr[j]; arr[j] = t; } private static void swap(int[] arr, int i, int j) { int t = arr[i]; arr[i] = arr[j]; arr[j] = t; } }
public class QuickSort2Ways { private QuickSort2Ways() { } // 双路快速排序 public static <E extends Comparable<E>> void quickSort2ways(E[] arr) { Random random = new Random(); quickSort2ways(arr, 0, arr.length - 1, random); } private static <E extends Comparable<E>> void quickSort2ways(E[] arr, int l, int r, Random random) { if (l >= r) return; int p = partition(arr, l, r, random); quickSort2ways(arr, l, p - 1, random); quickSort2ways(arr, p + 1, r, random); } private static <E extends Comparable<E>> int partition(E[] arr, int l, int r, Random random) { int p = l + random.nextInt(r - l + 1); swap(arr, l, p); // i指向<=的区间的下一个元素,j指向>=区间的前一个元素 int i = l + 1, j = r; while (true) { while (i <= j && arr[i].compareTo(arr[l]) < 0) { i++; } while (i <= j && arr[j].compareTo(arr[l]) > 0) { j--; } // 循环条件:i<j;相反就是结束条件 if (i >= j) { break; } // 循环未结束,此时arr[i]>=基数,arr[j]<=基数,交换使得前小后大 swap(arr, i, j); // 移动指针 i++; j--; } // 循环跳出条件i>=j,arr[j]指向<=arr[l]的最后一个数,交换(l,j) swap(arr, l, j); return j; } private static <E> void swap(E[] arr, int i, int j) { E t = arr[i]; arr[i] = arr[j]; arr[j] = t; } }
public class QuickSort3Ways { private QuickSort3Ways() { } // 三路快排 public static <E extends Comparable<E>> void quickSort3ways(E[] arr) { Random random = new Random(); quickSort3ways(arr, 0, arr.length - 1, random); } private static <E extends Comparable<E>> void quickSort3ways(E[] arr, int l, int r, Random random) { if (l >= r) return; int p = l + random.nextInt(r - l + 1); swap(arr, l, p); // 核心:arr[l+1,lt]<v ; arr[lt+1,i-1]=v ; arr[gt,r]>v // less指向<的最后一个元素,i指针遍历,more指向>的第一个元素 int less = l, i = l + 1, more = r + 1; while (i < more) { if (arr[i].compareTo(arr[l]) < 0) { less++; swap(arr, i, less); i++; } else if (arr[i].compareTo(arr[l]) > 0) { more--; swap(arr, i, more); // 原先的gt--后的值没有比较过,i继续指向它,不用i++ } else { // arr[i]==arr[l] i++; } } swap(arr, l, less); // 三路快排抛弃掉中间的部分,再也不递归 quickSort3ways(arr, l, less - 1, random); quickSort3ways(arr, more, r, random); } private static <E> void swap(E[] arr, int i, int j) { E t = arr[i]; arr[i] = arr[j]; arr[j] = t; } }
public class Solution { // 排序法 public int majorityElement(int[] nums) { Arrays.sort(nums); return nums[nums.length / 2]; } // map法 public int majorityElement1(int[] nums) { Map<Integer, Integer> map = countMap(nums); for (Map.Entry<Integer, Integer> entry : map.entrySet()) { if (entry.getValue() > (nums.length) / 2) { return entry.getKey(); } } throw new RuntimeException("not have num"); } private Map<Integer, Integer> countMap(int[] nums) { Map<Integer, Integer> map = new HashMap<>(); for (int num : nums) { if (!map.containsKey(num)) { map.put(num, 1); } else { map.put(num, map.get(num) + 1); } } return map; } // 候选人投票法 public int majorityElement2(int[] nums) { int res = nums[0], res_count = 1; for (int i = 1; i < nums.length; i++) { if (res == nums[i]) { res_count++; } else { res_count--; if (res_count == 0) { // 候选人投票数为0,重置候选人为下一个数 res = nums[i]; res_count = 1; } } } return res; } }
public class HeapSort { private HeapSort() { } // 基础知识:设根节点0开始为i,左孩子2i+1,右孩子2i+2 // 设左右孩子为i,父亲节点为(i-1)/2 // 堆排序:原地堆排序 public static <E extends Comparable<E>> void heapSort(E[] arr) { if (arr.length <= 1) { return; } // 1.对数组最右子树父节点依次上浮操做,循环结束arr[0]=数组max for (int i = (arr.length - 1 - 1) / 2; i >= 0; i--) { siftUp(arr, i, arr.length); } // 2.第一次arr[0]=max,与数组末尾交换,每次交换,都对[0,i)进行下沉操做使得arr[0]=max for (int i = arr.length - 1; i >= 0; i--) { swap(arr, 0, i); siftUp(arr, 0, i); } } // 对 arr[0,bound)所造成的最大堆中,索引为parentIndex的父亲和其左右孩子,进行最大值上浮操做 private static <E extends Comparable<E>> void siftUp(E[] arr, int parentIndex, int bound) { while (2 * parentIndex + 1 < bound) { int left = 2 * parentIndex + 1; if (left + 1 < bound && arr[left + 1].compareTo(arr[left]) > 0) { // left指向最大孩子节点下标 left++; } // 循环结束条件:父元素比孩子最大还大 if (arr[parentIndex].compareTo(arr[left]) >= 0) { break; } // 不然:交换父元数和孩子最大值 swap(arr, parentIndex, left); // 父指针指向孩子最大值下标 parentIndex = left; } } private static <E> void swap(E[] arr, int i, int j) { E t = arr[i]; arr[i] = arr[j]; arr[j] = t; } }
public class Solution { public ListNode mergeKLists(ListNode[] lists) { if (lists == null || lists.length == 0) { return null; } // 最小值堆:按照lists中node的值从小到大排列。相同的值按照原先顺序排列 PriorityQueue<ListNode> minQueue = new PriorityQueue<>(lists.length, (node1, node2) -> { if (node1.val < node2.val) { return -1; } else if (node1.val == node2.val) { return 0; } else { return 1; } }); // 哑结点和遍历指针 ListNode dummyNode = new ListNode(0); ListNode cur = dummyNode; // 遍历原lists,将全部结点放入最小值堆中 for (ListNode node : lists) { if (node != null) { minQueue.add(node); } } // 遍历最小值堆,每次让cur指向出队的元素,cur后移,再让cur.next从新入队,始终让堆顶保持最小值 while (!minQueue.isEmpty()) { cur.next = minQueue.poll(); cur = cur.next; if (cur.next != null) { minQueue.add(cur.next); } } return dummyNode.next; } }