分隔链表
| Category | Difficulty | Likes | Dislikes |
|---|---|---|---|
| algorithms | Medium (51.56%) | 106 | - |
Tags
Companies
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
/*
* @lc app=leetcode.cn id=86 lang=javascript
*
* [86] 分隔链表
*/
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} x
* @return {ListNode}
*/
var partition = function(head, x) {
};
1

把比x小的节点放在前面.大的放后面
先不说这题的话,很容易让我们想到快速排序里的主元
先不说有没有关系,就当练习一下自己写一个快速排序
然后仔细想想这里应该运用了归并排序里的写法
function mergeSort(arr) {
if (arr.length > 1) {
let len = arr.length
const left = mergeSort(arr.slice(0, len / 2))
const right = mergeSort(arr.slice(len / 2, len))
arr = merge(left, right)
}
return arr
}
function merge(left, right) {
const ret = []
let i = 0
let j = 0
while (i < left.length && j < right.length) {
ret.push(left[i] < right[j] ? left[i++] : right[j++])
}
return ret.concat(i < left.length ? left.slice(i) : right.slice(j))
}
其实也没多大关系,只刚好上面有分队后再合并.
那我们完全可以使用同样的套路
创建两个链表left和right,然后便利链表,把比x小的数放在left链表,大的数放在right链表,最后合并两链表即可.
var partition = function (head, x) {
let left = new ListNode('left') // 这里传参只是为了画图好看
let right = new ListNode('right') // 这里传参只是为了画图好看
let lCur = left
let rCur = right
while (head) {
if (head.val < x) {
lCur.next = head
lCur = head
} else {
rCur.next = head
rCur = head
}
head = head.next
}
lCur.next = right.next
rCur.next = null
return left.next
};

后面通过判断把遍历的接点存在在新的链表上,这是不难的
但是有个细节特别容易导致出错

我们在对节点分大小的时候,我们只是改变lCur和rCur指向哪里,而未对被分类的节点进行操作
只有再再次改变lCur的时候,上次分类的节点就会被改变next
但是刚被分类的节点的next是没有改变的,注意上图中5的next指向,因为当head分完时,我们已经没有再控制5节点了
此时的5节点指向的是2
那我们在合并的时候就需要注意了

lCur.next = right.next
如果此时我们直接返回
return left.next
那这个链表是一个带环型的,与答案是不符合的
所以我们需要补充

rCur.next = null