目录
基本概念
递归算法(英语:recursion algorithm)在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。递归式方法可以被用于解决很多的计算机科学问题,因此它是计算机科学中十分重要的一个概念。绝大多数编程语言支持函数的自调用,在这些语言中函数可以通过调用自身来进行递归。计算理论可以证明递归的作用可以完全取代循环,因此在很多函数编程语言(如Scheme)中习惯用递归来实现循环。
- 找整个递归的终止条件:递归应该在什么时候结束?
- 找返回值:应该给上一级返回什么信息?
- 本级递归应该做什么:在这一级递归中,应该完成什么任务?
探索
记忆化
通常情况下,递归是一种直观而有效的实现算法的方法。 但是,如果我们不明智地使用它,可能会给性能带来一些不希望的损失,比如重复计算。为了避免这个问题我们提出了记忆化。(可以理解为用空间来换时间)
记忆化是一种优化技术,主要用于加快计算机程序的速度,方法是存储昂贵的函数调用的结果,并在相同的输入再次出现时返回缓存的结果。 (来源: 维基百科)
斐波那契数,通常用
F(n)
表示,形成的序列称为斐波那契数列。该数列由0
和1
开始,后面的每一项数字都是前面两项数字的和。也就是:F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定
N
,计算F(N)
。
用哈希表存储算过的结果,这样可以避免重复运算
class Solution {
HashMap<Integer,Integer> cache=new HashMap<Integer,Integer>();//用哈希表存储算过的结果,这样可以避免重复运算
public int fib(int N) {
if(cache.containsKey(N)){
return cache.get(N);
}
int res;
if(N<2){
res=N;
}else{
res=fib(N-1)+fib(N-2);
}
cache.put(N,res);
return res;
}
}
时间复杂度
给出一个递归算法,其时间复杂度通常是递归调用的数量(R)和计算的时间复杂度(O(s))的乘积:O(T)=R.O(s)
记忆化技术不仅可以优化算法的时间复杂度,还可以简化时间复杂度的计算。
空间复杂度
计算空间复杂度,需考虑造成空间消耗的两个部分:递归相关空间和非递归相关空间
力扣题
206. 反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;//结束递归
ListNode p = reverseList(head.next);
head.next.next = head;//4->5->4
head.next = null;//切断得到5->4
return p;//返回5
}
时间复杂度:O(n),假设 n 是列表的长度,那么时间复杂度为O(n)。
递归和迭代的区别
public ListNode reverseList(ListNode head) {//迭代算法
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
21. 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1==null) return l2;//设置递归中止条件
else if(l2==null) return l1;
else if(l1.val<l2.val)
{
l1.next=mergeTwoLists(l1.next,l2);
return l1;
}
else
{
l2.next=mergeTwoLists(l1,l2.next);
return l2;
}
}
}