剑指 Offer 10- I. 斐波那契数列
笨办法示例(超时):
class Solution:
def fib(n: int) -> int:
num = 0
if n==0:
return 0
elif n == 1:
return 1
else:
num = num + Solution.fib(n-1) + Solution.fib(n-2)
return num % 1000000007
动态规划:
动态规划最简单的题目,而且直接给出了数学公式,dp[i]=dp[i-1]+dp[i-2]。
class Solution:
def fib(n: int) -> int:
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a % 1000000007
剑指 Offer 62. 圆圈中最后剩下的数字
面试题 02.03. 删除中间节点
这题的核心思想其实就是把node的下一位的值覆盖给node,然后跳过node的下一位
因为我们无法访问到head节点,所以除了直接从node开始往下找,其他都是不现实的
即
a->b->c->d->e->f 变为 a->b->d->d->e->f 然后把第一个d的next设为e,跳过第二个d
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
node.val = node.next.val
node.next = node.next.next
递归:
class Solution:
def mergeTwoLists(self, l1, l2):
if l1 is None:
return l2
elif l2 is None:
return l1
elif l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
迭代:
class Solution:
def mergeTwoLists(self, l1, l2):
prehead = ListNode(-1)
prev = prehead
while l1 and l2:
if l1.val <= l2.val:
prev.next = l1
l1 = l1.next
else:
prev.next = l2
l2 = l2.next
prev = prev.next
# 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
prev.next = l1 if l1 is not None else l2
return prehead.next
24. 两两交换链表中的节点
递归
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
newHead = head.next
head.next = self.swapPairs(newHead.next)
newHead.next = head
return newHead
迭代
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
dummyHead = ListNode(0)
dummyHead.next = head
temp = dummyHead
while temp.next and temp.next.next:
node1 = temp.next
node2 = temp.next.next
temp.next = node2
node1.next = node2.next
node2.next = node1
temp = node1
return dummyHead.next
82. 删除排序链表中的重复元素 II
递归
class Solution(object):
def deleteDuplicates(self, head):
if not head or not head.next:
return head
if head.val != head.next.val:
head.next = self.deleteDuplicates(head.next)
else:
move = head.next
while move and head.val == move.val:
move = move.next
return self.deleteDuplicates(move)
return head
迭代
class Solution(object):
def deleteDuplicates(self, head):
if not head or not head.next:
return head
dummy = ListNode(0)
dummy.next = head
pre = dummy
cur = head
while cur:
# 跳过当前的重复节点,使得cur指向当前重复元素的最后一个位置
while cur.next and cur.val == cur.next.val:
cur = cur.next
if pre.next == cur:
# pre和cur之间没有重复节点,pre后移
pre = pre.next
else:
# pre->next指向cur的下一个位置(相当于跳过了当前的重复元素)
# 但是pre不移动,仍然指向已经遍历的链表结尾
pre.next = cur.next
cur = cur.next
return dummy.next
779. 第K个语法符号
递归+寻找规律法:每一行的后半部分都是前半部分的翻转。
第一行: 0
第二行: 01
第三行: 0110
第四行: 01101001
第5行: 0110100110010110
第6行: 01101001100101101001011001101001
class Solution:
def kthGrammar(self, N: int, K: int) -> int:
if N == 1: return 0
# 计算上一行的长度(本行长度折半)
prevLen = (1 << (N - 1)) // 2
if K <= prevLen:
# 位于前半段,则等价于上一行同样位置的值
return self.kthGrammar(N-1, K)
else:
# 位于后半段,则等价于上一行相应位置的值取反
return 1 - self.kthGrammar(N-1, K-prevLen)
class Solution(object):
def kthGrammar(self, N, K):
if N == 1: return 0
if K <= (2**(N-2)):
return self.kthGrammar(N-1, K)
return self.kthGrammar(N-1, K - 2**(N-2)) ^ 1
复杂度分析
-
时间复杂度: O(N)。
-
空间复杂度: O(1)。