1.给出一个链表的head,判断该链表是否为回文结构,要求S(n) = 1,T(n) = n
//方法一:T(n) = n,S(n) = 1
function f(head){
if(!head||!head.next) return true
let res = true
let n1 = head
let n2 = head
let n3 = null
// 1.利用快慢指针找出中间点n1
while (n2.next&&n2.next.next) {
n1 = n1.next
n2 = n2.next.next
}
// 2.反转右侧
n2 = n1.next
n1.next = null
while (n2) {
n3 = n2.next
n2.next = n1
n1 = n2
n2 = n3
}
// 3.判断是否回文
n3 = n1 // 这里是为了遍历完之后恢复原链表结构
n2 = head
while (n1&&n2) {
if(n1.value!==n2.value) {
res = false
break
}
n1 = n1.next
n2 = n2.next
}
// 4.恢复原结构,再反转右侧
n1 = n3
n2 = n1.next
n1.next = null
while(n2){
n3 = n2.next
n2.next = n1
n1 = n2
n2 = n3
}
return res
}
// 方法二:T(n) = n,S(n) = n,最笨的方法
function f(head){
let stack = []
let cur = head
while(cur){
stack.push(cur)
cur = cur.next
}
cur = head
while(cur){
if(cur.value!==stack.pop().value) return false
cur = cur.next
}
return true
}
// 方法三:T(n) = n,S(n) = n/2
function f(head){
if(!head||!head.next) return true
let stack = []
let n1 = head
let n2 = head
while(n2.next&&n2.next.next){
n1 = n1.next
n2 = n2.next.next
}
n1 = n1.next // 中点的下一点
while (n1) {
stack.push(n1)
n1 = n1.next
}
while(stack.length){
if(head.value!==stack.pop().value) return false
head = head.next
}
return true
}
2.给出一个链表的head,要求链表按照一个给定值,按小于、等于、大于排列,要求S(n) = 1,T(n) = n
// 方法一:T(n) = n,S(n) = n,不稳定
function f(head,n) {
let arr = []
let next = null
while (head) {
next = head.next
head.next = null
arr.push(head)
head = next
}
partition(arr,n) // 荷兰国旗 partition
let h = a = arr.shift()
while (arr.length) {
a.next = arr.shift()
a = a.next
}
return h
}
function partition(arr,n,l=0,r=arr.length-1) {
let min = l-1
let max = r+1
while (l<max) {
if(arr[l].value<n) swap(arr,l++,++min)
else if(arr[l].value>n) swap(arr,l,--max)
else l++
}
}
function swap(arr,i,j) {
[arr[i],arr[j]] = [arr[j],arr[i]]
}
// 方法二:T(n) = n,S(n) = 1,稳定
function f(head,n){
let sh=st=eh=et=bh=bt=next=null
while (head) {
next = head.next
head.next = null
if(head.value<n){
if(!sh){
sh = st = head
}else{
st.next = head
st = head
}
}
else if(head.value==n){
if(!eh){
eh = et = head
}else{
et.next = head
et = head
}
}
else if(head.value>n){
if(!bh){
bh = bt = head
}else{
bt.next = head
bt = head
}
}
head = next
}
if(st){
st.next = eh
et = et||et
}
if(et){
et.next = bh
}
return sh||eh||bh
}
3.复制一个带有random指针的链表
// 方法一:T(n) = n,S(n) = n
function f(head) {
let cur = head
let map = new Map() // use map
while (cur) { // copy value
map.set(cur, {value:cur.value})
cur = cur.next
}
cur = head
while (cur) { // copy next&random
map.get(cur).next = map.get(cur.next)
map.get(cur).random = map.get(cur.random)
}
return map.get(head)
}
// 方法二:T(n) = n,S(n) = 1
function f(head) {
// 1-1-2-2-3-3
let cur = head
while (cur) {
let {value,next} = cur
cur.next = {value}
cur.next.next = next
cur = next
}
// random
cur = head
while (cur) {
let {next} = cur
next.random = cur.random?cur.random.next:null // 边界
cur = next.next
}
// 1-2-3 1-2-3
cur = head
let h = a = cur.next
while (cur) {
cur.next = cur.next.next
a.next = a.next?a.next.next:null // 边界
cur = cur.next
a = a.next
}
return h
}
4.找出两链表(可能有环loop)的相交节点,要求:T(n)=n,S(n)=1
// 主函数
function findMergeNode(head1,head2) {
let loop1 = getLoop(head1)
let loop2 = getLoop(head2)
if(!loop1&&!loop2) return noLoop(head1,head2)
if(loop1&&loop2) return bothLoop(head1,head2,loop1,loop2)
return null // 一个有环一个无环必不可能相交
}
// 找loop
function getLoop(head) {
if(!head||!head.next||!head.next.next) return null
let n1 = head.next
let n2 = head.next.next
while (n2.next&&n2.next.next) {
n1 = n1.next
n2 = n2.next.next
if(n1===n2) {
n2 = head
while (n2!==n1) {
n1 = n1.next
n2 = n2.next
}
return n1
}
}
return null
}
// 都无环的情况
function noLoop(head1,head2) {
if(!head1||!head1.next||!head2||!head2.next) return null
let step = 0 // step == n1.len - n2.len
let n1 = head1
let n2 = head2
while (n1.next) {
step++
n1 = n1.next
}
while (n2.next) {
step--
n2 = n2.next
}
if(n1!==n2) return null
n1 = step>0?head1:head2
n2 = step>0?head2:head1
step = Math.abs(step)
while (step) {
step--
n1 = n1.next
}
while (n1!==n2) {
n1 = n1.next
n2 = n2.next
}
return n1
}
// 都有环的情况
function bothLoop(head1,head2,loop1,loop2) {
let n1 = null
let n2 = null
if(loop1==loop2){ // 情况1:两环相等必相交
let step = 0
n1 = head1
n2 = head2
while (n1!==loop1) {
step++
n1 = n1.next
}
while (n2!==loop2) {
step--
n2 = n2.next
}
n1 = step>0?head1:head2
n2 = step>0?head2:head1
step = Math.abs(step)
while (step) {
step--
n1 = n1.next
}
while(n1!==n2){
n1 = n1.next
n2 = n2.next
}
return n1
}
// 情况2:两环不等,从任意loop开始,若绕一圈还是没碰头,证明没有相交点
n1 = loop1.next
while (n1!==loop1) {
if(n1===loop2) return loop2
n1 = n1.next
}
return null
}