1623403185(1).png
一句话概括就是:将链表以x为标定点分隔成两部分
既然是 2 部分,就可以开两个链表,来跟踪每一部分,最后处理完再合并下即可。
public ListNode partition(ListNode head, int x) {
ListNode lh = new ListNode(-1), lt = lh;
ListNode rh = new ListNode(-1), rt = rh;
for(ListNode p = head; p != null; p = p.next) {
if(p.val < x) lt = lt.next = p;
else rt = rt.next = p;
}
lt.next = rh.next;
rt.next = null;
return lh.next;
}
随后,怎么感觉这种处理链表的技巧好像在哪见过,很熟悉。然后就相当了 JDK1.8 hashmap扩容用的逻辑非常像,请看:
hashmap8扩容细节.png
红框和蓝框的两段是不是非常的眼熟,这两端在hashmap中作用是什么?
毫无疑问,那就是同分隔链表这题一样,就是分隔链表。
hashmap8扩容方式
hashmap8的扩容方式与7有些不同
- 7的方式是,每次都是调用
e.hash & (newCap - 1)
这种方式重新计算hash,讲道理这种方式并没什么问题,但对于追求极致性能的开发者来说,这样方式有些简单粗暴,直来直去,不能忍! - 8的方式,8好像意识到了什么,每次扩容,新容量为原容量的两倍,站在二进制的角度来看,无非就是新容量后面多了一个0,比如 16 = 2^4 = 10000, 32 = 2^5 = 100000,拿该例来说,通过对比发现 低4位是不变的, 变化的是 第5位,说明扩容后位置不变。
因此可以得出一个结论: 扩容之后,老元素要么原位不动,要么原始位置 + oldSize(16)
解释下为什么会有:原始位置 + oldSize???
还拿上面的例子来说,实际可能发生变化的只有第5位,通过什么方式判断第5位有没有变化?
可以用 e.hash & oldCap
来判断,如果结果为0,说明扩容之后还在原始位置,如果为1,说明产生了变动,这里在进一步解释一下 为什么0表示没变动?这到底是为什么?
我们知道 进行 与
运算时,0无论与1 还是 0 ,即0 & 1 = 0,0 & 0 = 0, 结果都是0,然后再加上后四位都一样的情况,那么就可以得出,如果第5位与e.hash的结果为0 。
回到Leetcode86
从图中的代码中可以看到,本质是通过,第5位
是0,还是1,将一个链表分割成两份