递归算法
1. 原则
1.1 递归三要素
1. 明确函数功能,先不管函数里面的代码逻辑是什么,首先要明确自己定义的函数用来干什么
2. 寻找递归结束条件,递归就是就是函数自己调用自己,不然就是就会出现死循环,最终导致栈溢出StackOveflowError
3. 寻找函数的等价关系式,不断的缩小参数范围
1.2 重要规则
1. 执行一个方法时,就是创建一个新的受保护的独立空间(栈空间)
2. 方法的局部变量是独立的,不受递归次数的影响
3. 方法中的引用类型变量是全局共享的,例如数组,hashmap等;
4. 当一个方法执行完毕的时候(或者return)遵守谁调用就将结果返回给谁
5. 递归分为递和归两步
2. 递归示例
2.1 斐波那契数列
public class Fibonacci { public static void main(String[] args) { int[] arr = new int[10000]; System.out.println(fib(10)); System.out.println(fib2(arr, 10)); } /** * 求Fibonacci数列前n项和 f(n)=f(n-1)+f(n-2) * Fibonacci数列:1,1,2,3,5,8,13..。 * 1.明确函数功能 * 2.寻找递归结束条件 * 3.寻找函数的等价关系式 * * @param n * @return */ public static int fib(int n) { if (n == 1 || n == 2) { return 1; } return fib(n - 1) + fib(n - 2); } /** * 递归优化,避免重复计算 * @param arr 状态保存 * @param n * @return */ public static int fib2(int[] arr, int n) { if (n == 1 || n == 2) { return 1; } //已经计算过,直接返回 if (arr[n - 1] != 0) { return arr[n - 1]; } arr[n - 1] = fib(n - 1) + fib(n - 2); return arr[n - 1]; } }
2.2 反转单链表
例如链表为:1->2->3->4,反转后为 4->3->2->1
常规思路:遍历链表,treemap存储(key=node,value=next),遍历map,修改key和value顺序,并修改最后一个node的next=null
第二种思路是:通过递归反转,递归的本质就是找等价关系式,或者是规律,分析如下
递:
1>2>3>4
2>3>4
3>4
4
归:
4>3
4>3>2
4>3>2>1
public class Digui { public static void main(String[] args) { Node node3 = new Node(4, null); Node node2 = new Node(3, node3); Node node1 = new Node(2, node2); Node head = new Node(1, node1); System.out.println(reverseList(head)); } /** * 反转单链表 1->2->3->4 * * @param head * @return */ public static Node reverseList(Node head) { if (head == null || head.next == null) { return head; } Node newHead = reverseList(head.next); Node tmp = head.next; tmp.next = head; head.next = null; return newHead; } } @Data @AllArgsConstructor @ToString class Node { int data; Node next; }