142. 环形链表 II
题目
找出环形链表的入口
分析
典型快慢指针追及问题(每次快指针走两步,慢指针走一步),难点在于如何找到环的入口,快慢指针第一次相遇时的节点并不一定是环的入口
将链表从入口处截断,前半段距离为a,后半段为环距离为b,快指针走的距离为f,慢指针走的距离为s,
快慢指针相遇时,快指针走的距离一定比慢指针多n圈,即f -s = nb,同时f速度为s的2倍,即 f = 2s,则 s = nb
要找到环的入口点,在于如何让两个指针相遇在入口,此时慢指针走了nb,若再走a,则到达环的入口(s = a + nb),那么a是取得呢,
显然让一个指针从头开始走a,也是到达入口点,因此在快慢指针第一次相遇之后,一个新的指针同时开始走,当新指针与慢指针相遇时,即为入口
总结:
- 快慢指针,不相遇为无环,相遇有环
- 此时新的指针每次和慢指针走同样速度,相遇时即为环的入口
fun detectCycle(head: ListNode?): ListNode? {
if (head == null) return null
var fast = head
var slow = head
while (fast!!.next != null && fast.next!!.next != null) {
fast = fast.next!!.next
slow = slow!!.next
if (fast == slow) {
fast = head
while (fast != slow) {
fast = fast!!.next
slow = slow!!.next
}
return fast
}
}
return null
}
21.合并两个有序链表
模拟合并简单题,不做陈述
fun mergeTwoLists(list1: ListNode?, list2: ListNode?): ListNode? {
var curr1 = list1
var curr2 = list2
var result = ListNode(0)
var curr = result
while (curr1 != null && curr2 != null) {
when {
curr1.`val` > curr2.`val` -> {
curr.next = curr2
curr = curr2
curr2 = curr2.next
}
else -> {
curr.next = curr1
curr = curr1
curr1 = curr1.next
}
}
}
var temp = curr1 ?: curr2
while (temp != null) {
curr.next = temp
curr = temp
temp = temp.next
}
return result.next
}
2. 两数相加
模拟相加简单题,不做陈述
fun addTwoNumbers(l1: ListNode?, l2: ListNode?): ListNode? {
val result = ListNode(0)
deep(l1, l2, result)
return result.next
}
fun deep(l1: ListNode?, l2: ListNode?, curr: ListNode, add: Int = 0) {
when {
l1 == null && l2 == null -> {
add.takeIf { it != 0 }?.let { curr.next = ListNode(add) }
}
l1 == null -> {
curr.next = ListNode((l2!!.`val` + add) % 10)
deep(null, l2.next, curr.next!!, (l2.`val` + add) / 10)
}
l2 == null -> {
curr.next = ListNode((l1.`val` + add) % 10)
deep(l1!!.next, null, curr.next!!, (l1.`val` + add) / 10)
}
else -> {
curr.next = ListNode((l1.`val` + l2.`val` + add) % 10)
deep(l1.next, l2.next, curr.next!!, (l1.`val` + l2.`val` + add) / 10)
}
}
}
关于我
一个希望友友们能提出建议的代码下毒糕手