剑指 Offer 18. 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。题目保证链表中节点的值互不相同。
pre、node分别指前一个节点、要判断的节点
class Solution:
def deleteNode(self, head: ListNode, val: int) -> ListNode:
if head.val == val: return head.next
pre, node = head, head.next
while node:
if node.val==val:
pre.next = node.next
node = pre.next
else:
pre = node
node = node.next
return head
剑指 Offer 22. 链表中倒数第k个节点
倒数第三个,k=3
- - - - - - - None
- - - - k - - None
i. - - j. - - - None
class Solution:
def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
i = j = head
for _ in range(k):
if j:
j = j.next
else: return i # k比链表长
while j:
i=i.next
j=j.next
return i
剑指 Offer 25. 合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
我的要判断条件,以l1或者l2为头。参考答案自己生成一个头节点,不需要多余的判断语句。
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if not l1: return l2
if not l2: return l1
if l1.val <= l2.val:
head = l1
l1 = l1.next
else:
head = l2
l2 = l2.next
cur = head
while l1 and l2:
if l1.val < l2.val:
cur.next, l1 = l1, l1.next
else:
cur.next, l2 = l2, l2.next
cur = cur.next
cur.next = l1 if l1 else l2
return head
参考答案
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
cur = dum = ListNode(0)
while l1 and l2:
if l1.val < l2.val:
cur.next, l1 = l1, l1.next
else:
cur.next, l2 = l2, l2.next
cur = cur.next
cur.next = l1 if l1 else l2
return dum.next
剑指 Offer 52. 两个链表的第一个公共节点
该题想不到,涉及巧妙的数学计算,与下面找到环形入口相似。
解释: 这里把最后None也当成节点
两个链表长度分别为L1+C、L2+C, C为公共部分的长度,按照楼主的做法: 第一个人走了L1+C步后,回到第二个人起点走L2步;第2个人走了L2+C步后,回到第一个人起点走L1步。 当两个人走的步数都为L1+L2+C时就相遇了。
不相交的情况设A链表长度是a B链表长度是b 最后a+b = b+a 所以一定是一起走到None这个节点。可以理解为两条链表最后都指向了同一个 null (None)节点,代替了不相交的特殊情况。 非常的巧妙。
而不是
node1 = node1.next if node1.next else headB
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
node1, node2 = headA, headB
while node1 != node2:
node1 = node1.next if node1 else headB # 当node1走到A的None节点,它下一步到B
node2 = node2.next if node2 else headA
# A和B等长时,第一遍就知道结果
return node1
leetcode142. 环形链表 II
https://leetcode-cn.com/problems/linked-list-cycle-ii/
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
总结:
f=2s (快指针每次2步,路程刚好2倍)
f = s + nb (相遇时,刚好多走了n圈)
推出1. 第一次相遇,slow = nb
2. 从head结点走到入环点需要走 : a + nb
3. 而slow已经走了nb,那么slow再走a步就是入环点了。
4. 由3得出,起始距离入口 = 第一次相遇位置 + a
如何知道slow刚好走了a步? 从head开始,和slow指针一起走,相遇时刚好就是a步
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
fast, slow = head, head
while True:
if not (fast and fast.next): return None
fast, slow = fast.next.next, slow.next
if fast == slow: break
fast = head
while fast != slow:
fast, slow = fast.next, slow.next
return fast
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
x&1 位运算 等价于 x % 2x%2 取余运算,即皆可用于判断数字奇偶性。
class Solution:
def exchange(self, nums: List[int]) -> List[int]:
i, j = 0, len(nums)-1
while i<j: # 可能不在这发生i==j
while i<j: # 不能等于,当i==j就会结束
if nums[i]%2==1: i+=1
else: break
while j>i:
if nums[j]%2==0: j-=1
else: break
if i!=j:
tmp = nums[i]
nums[i] = nums[j]
nums[j] = tmp
return nums
class Solution:
def exchange(self, nums: List[int]) -> List[int]:
i, j = 0, len(nums) - 1
while i < j:
while i < j and nums[i] & 1 == 1: i += 1
while i < j and nums[j] & 1 == 0: j -= 1
nums[i], nums[j] = nums[j], nums[i]
return nums
剑指 Offer 57. 和为s的两个数字
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
i, j = 0, len(nums) - 1
while i < j:
s = nums[i] + nums[j]
if s > target: j -= 1
elif s < target: i += 1
else: return nums[i], nums[j]
return []
剑指 Offer 58 - I. 翻转单词顺序
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。
有两个细节处理
方法一:
利用 “字符串分割”、“列表倒序” 的内置函数 (面试时不建议使用) ,可简便地实现本题的字符串翻转要求。
class Solution:
def reverseWords(self, s: str) -> str:
s = s.strip() # 删除首尾空格
strs = s.split() # 分割字符串
strs.reverse() # 翻转单词列表 # [::-1]也是倒序
return ' '.join(strs) # 拼接为字符串并返回
方法二:双指针,以单词为单位,找出每个单词作为列表元素
class Solution:
def reverseWords(self, s: str) -> str:
s = s.strip() # 删除首尾空格
i = j = len(s) - 1
res = []
while i >= 0:
while i >= 0 and s[i] != ' ': i -= 1 # 搜索首个空格
res.append(s[i + 1: j + 1]) # 添加单词
while s[i] == ' ': i -= 1 # 跳过单词间空格 # i=-1 其实指最后一个
j = i # j 指向下个单词的尾字符
return ' '.join(res) # 拼接并返回