第一题
23. 合并 K 个升序链表
本题是已经知道有多个链表,需要我们将这些链表按照升序排列的规则组合到一起,同时这些链表都是升序排列的;
解法一:
利用优先级队列
步骤一:利用优先级队列床架一个小根堆;
步骤二:将每一个链表的头结点放在小根堆里面;
步骤三:创建一个新节点,将第二不得堆顶的节点插入到新节点后面,同时将该节点所在的链表的后一个节点放在小根堆里面开始进行下一个循环;
细节:当小根堆的堆顶不为空时,一直要进行出栈操作;每一个链表的当前节点的下一个节点不为空,就会一直进行入堆操作;
综上分析,代码如下:
class Solution {public ListNode mergeKLists(ListNode[] lists) {//1、创建一个小根堆PriorityQueue <ListNode> heap = new PriorityQueue<>((v1,v2) -> v1.val - v2.val);//2、把所有的头结点放在小根堆中for(ListNode head : lists){if(head != null){heap.offer(head);}}//3、依次上堆顶的进入链表,合并链表ListNode ret = new ListNode(0);ListNode prev = ret;while(!heap.isEmpty()){ListNode t = heap.poll();prev.next = t;prev = t;if(t.next != null) heap.offer(t.next);}return ret.next;} }
解法二:使用分支-递归的思想
如上图是六个链表,我们采用分支的思想,分成两的部分,左部分和右部分,就这样一直分,直到被分的链表为一个或两个,我们就进行合并,将两个链表按照升序的规则一一合并,这样由小和大,慢慢的同一层级别的链表再次合并,这样,我们最后返回的链表就是这几个链表合并之后的升序大链表;
综上所述,代码如下:
class Solution {public ListNode mergeKLists(ListNode[] lists) {return merge(lists,0,lists.length-1);}public ListNode merge(ListNode[] lists,int left,int right ){if(left > right) return null;if(left == right) return lists[left];//1、平分数组int mid = (left + right )/2;//[left,mid],[mid+1,right]//2、递归处理左右两个部分ListNode l1 = merge(lists,left,mid);ListNode l2 = merge(lists,mid+1,right);//3、合并两个有序链表return mergeTwoList(l1,l2);}public ListNode mergeTwoList(ListNode l1,ListNode l2){if(l1 == null) return l2;if(l2 == null) return l1;//合并两个有序链表ListNode head = new ListNode(0);ListNode cur1 = l1,cur2 = l2,prev = head;while(cur1 != null && cur2 != null){if(cur1.val <= cur2.val){prev.next = cur1;prev = cur1;cur1 = cur1.next;}else{prev.next = cur2;prev = cur2;cur2 = cur2.next;}}if(cur1 != null) prev.next = cur1;if(cur2 != null) prev.next = cur2;return head.next;} }
第二题
25. K 个一组翻转链表
本题采用模拟的方法来解决:
步骤一:
遍历整个链表,求出整个链表的长度,计算出我们要逆序的链表为n组,且有多少个节点不需要遍历;
步骤二:
采用头插法,来插入n组长度为k的链表;
细节一:使用cur来指向原链表的头结点,即即将要插入的节点,用prev指针表示新链表指向被查位置的前一个节点
采用头插法插入:
首先定义指针next来指向下一个要插入的原链表的节点;
操作如上,插入完成后,next指针和cur指针分别向后移动一位;
重复上述操作,直到完成第一组的插入操作:
细节二:
此时我们定义一个tmp指针,指向每一组链表的第一个节点,当每一组链表被逆转之后,就将prev指针指向tmp指针,确保我们我们要插入的元素从prev指针开始逆转;
就这样,一直操作完n组,到了不需要逆转的几个节点组成的最后链表,直接添加即可;
故此,代码如下
class Solution {public ListNode reverseKGroup(ListNode head, int k) {//1、需要逆序的有几个组int n = 0;ListNode cur = head;while(cur != null){cur = cur.next;n++;}n /= k;//2、重复n次,长度为k的链表逆序操作ListNode newHead = new ListNode(0);ListNode prev = newHead;cur = head;for(int i = 0;i < n;i++){ListNode tmp = cur;for(int j = 0;j < k; j++){//开始头插ListNode next = cur.next;cur.next = prev.next;prev.next = cur;cur = next;}prev = tmp;}prev.next = cur;return newHead.next;} }
ps:本次的内容就到这里了,如果对你有所帮助的话,就请一键三连哦!!!