咋一看,仿佛和快排的partition过程,也就是荷兰国旗问题很类似,只是此处换成了单链表构造,实际上也的确能够采纳荷兰国旗问题来求解,只是此时的额定空间复杂度为O(N)。
1、采纳荷兰国旗问题求解:
(1)将链表放到数组中
(2)应用荷兰国旗办法将数组分为小于区、等于区、大于区
(3)将数组从新连成链表,返回头节点
/** * @author Java和算法学习:周一 */public static Node comparator(Node head, int pivot) { if (head == null) { return null; } // 获取链表节点数 Node current = head; int i = 0; while (current != null) { i++; current = current.next; } // 将链表放到数组中 Node[] arr = new Node[i]; current = head; for (i = 0; i < arr.length; i++) { arr[i] = current; current = current.next; } // 将数组分为小于区、等于区、大于区(外围就是荷兰国旗问题) partition(arr, pivot); // 将数组连成链表 for (i = 1; i < arr.length; i++) { arr[i - 1].next = arr[i]; } arr[i - 1].next = null; // 返回头节点 return arr[0];}private static void partition(Node[] arr, int pivot) { int small = -1; int big = arr.length; int index = 0; while (index < big) { if (arr[index].value < pivot) { swap(arr, ++small, index++); } else if (arr[index].value == pivot) { index++; } else { swap(arr, --big, index); } }}
2、额定空间复杂度为O(1)的解法:
(1)应用6个变量,顺次示意小于区头节点、尾结点,等于区头节点、尾结点,大于区头节点、尾结点
(2)遍历链表,把节点放到各个局部、同时调整尾结点
(3)将小于区 等于区 大于区 三块头尾连接起来
/** * @author Java和算法学习:周一 */public static Node smallerEqualBigger(Node head, int pivot) { // 小于区头节点 Node sH = null; // 小于区尾节点 Node sT = null; // 等于区头节点 Node eH = null; // 等于区尾节点 Node eT = null; // 大于区头节点 Node bH = null; // 大于区尾节点 Node bT = null; // 标记以后遍历的next节点 Node next = null; // 将链表分成 小于区 等于区 大于区 三块 while (head != null) { // 记录next节点 next = head.next; // 以后节点next节点置空 head.next = null; if (head.value < pivot) { // 小于区 if (sH == null) { // 如果是小于区的第一个节点,则小于区的头尾节点都指向以后节点 sH = head; sT = head; } else { // 如果不是小于区的第一个节点,则小于区的尾结点指向以后节点,调整尾结点 // 即在以后区内将各节点再次连接起来 sT.next = head; sT = head; } } else if (head.value == pivot) { // 等于区 if (eH == null) { // 如果是等于区的第一个节点,则等于区的头尾节点都指向以后节点 eH = head; eT = head; } else { // 如果不是等于区的第一个节点,则等于区的尾结点指向以后节点,调整尾结点 eT.next = head; eT = head; } } else { // 大于区 if (bH == null) { // 如果是大于区的第一个节点,则大于区的头尾节点都指向以后节点 bH = head; bT = head; } else { // 如果不是大于区的第一个节点,则大于区的尾结点指向以后节点,调整尾结点 bT.next = head; bT = head; } } // 以后节点挪动到next节点 head = next; } // 将小于区 等于区 大于区 三块头尾连接起来 // 小于区存在 if (sT != null) { // 则小于区尾节点连贯等于区头节点 sT.next = eH; // 如果此时等于区尾结点为空(即整个等于区为空),那么等于区的尾结点则为小于区尾结点 // 如果此时等于区尾结点不为空,那么等于区的尾结点就是之前的尾结点 eT = eT == null ? sT : eT; } // 有等于区,eT 就是等于区的尾结点 // 无等于区,有小于区,eT 就是小于区的尾结点 // 无等于区,无小于区,eT 就是空 if (eT != null) { // 则等于区的尾结点连贯大于区头节点 eT.next = bH; } // 最初返回以后的头节点 // 有小于区,返回小于区头节点 // 无小于区,有等于区,返回等于区头节点 // 无小于区,无等于区,有大于区,返回大于区头节点 return sH != null ? sH : (eH != null ? eH : bH);}
本文所有代码:https://github.com/monday-pro/algorithm-study/tree/master/src/basic/node