这道题被爱学习的你看到了,很棒!那今天就花十五分钟的时间,一起来看下链表中的节点每k个一组翻转。来说下解题思路:
将一个数组每次划分成等长的两部分,对两部分进行排序即是子问题。对子问题继续划分,直到子问题只有1个元素。还原的时候,将每个子问题和它相邻的另一个子问题利用上述双指针的方式,1个与1个合并成2个,2个与2个合并成4个,因为这每个单独的子问题合并好的都是有序的,直到合并成原本长度的数组。
对于这k个链表,就相当于上述合并阶段的k个子问题,需要划分为链表数量更少的子问题,直到每一组合并时是两两合并,然后继续往上合并,这个过程基于递归:
- 终止条件: 划分的时候直到左右区间相等或左边大于右边。
- 返回值: 每级返回已经合并好的子问题链表。
- 本级任务: 对半划分,将划分后的子问题合并成新的链表。
具体做法:
- step 1:从链表数组的首和尾开始,每次划分从中间开始划分,划分成两半,得到左边n/2个链表和右边n/2个链表。
- step 2:继续不断递归划分,直到每部分链表数为1个节点。
- step 3:将划分好的相邻两部分链表,按照两个有序链表合并的方式合并,合并好的两部分继续往上合并,直到最终合并成一个链表。
class Solution {
public:
ListNode* Merge2(ListNode* pHead1, ListNode* pHead2) {
if (pHead1 == NULL)
return pHead2;
if (pHead2 == NULL)
return pHead1;
ListNode* head = new ListNode(0); //加一个表头
ListNode* cur = head;
while (pHead1 && pHead2) { //两个链表都不为空时,取较小值的节点
if (pHead1->val <= pHead2->val) {
cur->next = pHead1; //只移动取值的指针
pHead1 = pHead1->next;
} else {
cur->next = pHead2; //只移动取值的指针
pHead2 = pHead2->next;
}
//指针后移
cur = cur->next;
}
if (pHead1)
cur->next = pHead1; //把剩下的接到后面
else
cur->next = pHead2;
return head->next; //返回值去掉表头
}
//划分合并区间函数
ListNode* divideMerge(vector<ListNode*>& lists, int left, int right) {
if (left > right)
return NULL;
else if (left == right)
return lists[left];
int mid = (left + right) /
2; //从中间分成两段,再将合并好的两段合并
return Merge2(divideMerge(lists, left, mid), divideMerge(lists, mid + 1,
right));
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
return divideMerge(lists, 0, lists.size() - 1); //k个链表归并排序
}
};