题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
思路
题目是要把所有重复的结点去掉,比如 1,1,1,2,3,3,4 变成 2,4,而不是 1,2,3,4
思路1
原地操作next指针,需要用到3个指针。由于头结点也可能会被删掉,所以还要创建一个虚拟头结点。
如果用不了3个指针,即链表元素不超过1个,则直接返回
(1)先创建头结点,i, j, k三个指针紧挨着
* -> 1 -> 1 -> 2 -> 3 -> 3 -> 4 -> null
↑ ↑ ↑
i j k
(2)让 k 尽量移远到不等于 j 的地方
* -> 1 -> 1 -> 2 -> 3 -> 3 -> 4 -> null
↑ ↑ ↑
i j k
(3)因为检测到有重复,所以修改 i 后继
* -----------> 2 -> 3 -> 3 -> 4 -> null
↑ ↑ ↑
i j k
(4)让 j, k 继续挨着 i
* -----------> 2 -> 3 -> 3 -> 4 -> null
↑ ↑ ↑
i j k
(5)重复第(2)步骤,发现检测不到重复,这个时候集体往后移
* -----------> 2 -> 3 -> 3 -> 4 -> null
↑ ↑ ↑
i j k
(6)重复第(2)步骤,检测到重复,修改 i 后继
* -----------> 2 -----------> 4 -> null
↑ ↑ ↑
i j k
(6)重复第(4)步骤,这时已经有个指针到尾了,程序结束
* -----------> 2 -----------> 4 -> null
↑ ↑ ↑
i j k
function deleteDuplication(pHead) {
if (!pHead || !pHead.next)
return pHead
// 因为头结点可能也是重复结点,所以要创建一个虚拟头结点
let root = new ListNode('virtual head')
root.next = pHead
// 利用3个指针,i, j, k三个初始为紧凑着
let i = root, j = root.next, k = root.next.next
while (i && j && k) {
// 尽量移远一点
let repeat = false
while (j && k && j.val == k.val) {
k = k.next
repeat = true
}
// 修改指针
if (repeat) {
// 如果有重复结点,那 i 的后继直接指向 k
i.next = k
} else {
// 没找到重复结点,i 直接往下一位
i = i.next
}
// i, j, k紧凑着
j = i.next
k = j ? j.next : null
}
// 输出虚拟头结点的后继
return root.next
}
思路2
将值存到一个栈中,如果当前入栈元素和栈顶元素相等,则不入栈且弹一次栈,最终将栈生成链表返回
function deleteDuplication(pHead) {
if (!pHead || !pHead.next)
return pHead
let stack = []
while (pHead) {
if (stack[stack.length - 1] != pHead.val) {
// 不重复元素直接入栈
stack.push(pHead.val)
pHead = pHead.next
} else {
// 出现重复元素
let repeat = stack.pop()
// 一直跳过重复元素
while (pHead && pHead.val == repeat) {
pHead = pHead.next
}
}
}
// 将栈转成链表
let root = stack.length ? new ListNode(stack[0]) : null
let p = root
for (let i = 1; i < stack.length; i++) {
p.next = new ListNode(stack[i])
p = p.next
}
return root
}