剑指Offer-2(动态算法)
求解决策过程(decision process)最优化的数学方法。
剑指10-1. 斐波那契数列
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
- 避免重复计算因此使用动态算法
class Solution: |
剑指10-2. 青蛙跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
- 本质还是斐波那契数列
- 注意当n=0时,因为只能不跳所以等于1(这个题的毛病不要太钻牛角尖)
class Solution: |
剑指16. 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
解题思路:
用list顺序存储单向链表,使用切片直接倒序输出。
Tip:
- 列表切片规则
List[start:stop:step]
,不加则是默认全部区间 List[::-1]
则代表倒置列表
复杂度
- 时间O(n), 空间O(n)
# Definition for singly-linked list. |
剑指24. 翻转链表(中转+递归)
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
解题思路:
需要解决的问题其实有两个:1. 如何改变node之间的指向 2. 如何保存头部节点
- 使用中转点对上一个node保存,遍历链表同时改变指向,最后一个到达的就是新链表的头部节点
- 递归。只有到达最后一个节点后才开始进行翻转。这里通过返回值不停传递末节点,即新链表的头结点。
- 传递参数:当前节点和下一节点
- 停止条件:当前节点为空
- 返回值:上一节点
- 执行动作:将下一节点指向当前节点
复杂度
- 时间:O(n),空间:O(2)
中转站法
# Definition for singly-linked list. |
- 时间:O(n),
- 空间:O(n):递归深度达到n,需要n的空间
递归
class Solution: |
剑指18. 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
时间O(n), 空间O(1)
# Definition for singly-linked list. |
剑指22. 链表中倒数第k个字节(快慢指针)
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
遍历法很容易想到就不在这里赘述了
- 时间O(n) 空间O(1)
# Definition for singly-linked list. |
剑指25. 合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
- 善用伪头结点可以减少很多步骤,如判断哪个才是头结点造成的代码行数增加
- 因为是链表结构而非数组,因此不用考虑最后剩下的需要用while再一个个塞进去
- 时间O(n), 空间O(1)
# Definition for singly-linked list. |