recursion
把问题分拆成一个一个更小的问题,最后汇总
一个简单的例子
//f(n) = f(n-1) + n;
public static int function(int n){
//base case 初始值
if (n == 0) {
return 0;
}
//function函数
return function(n-1) + n;
//所有数据存储在stack(栈)中
//一直到n==0,最后return 0, 才会往后慢慢加数据
//最后return function(n).
}
三个要素:
- 明确函数的功能,并且consistent
- 找出初始结束条件(n=0, n=1, n=2)
- 函数等价关系, f(n)和 f(n-1)…的关系
再来一个例子,这个例子的等价关系需要有前提条件
类似的例子还有factorial, power,都可以运用递归来构造 函数
然后 递推(从下往上)和递归(从上往下,先全轮一遍才返回,先递再归)的区别 是方向相反
但是递归有时候会造成空间与时间的极度浪费
- 超时
- 内存不够,Stack Overflow, 大量重复计算
所以需要优化
例题1:
出错,这里需要注意int的范围
int型的范围, 取值范围是【-2147483648 至2147483647) [-2^31, 2^31-1]
所以当取到2147483647的时候,报错
一种解法可以用long型替代int型,防止溢出。
再是指数分奇偶讨论,有效让n变小,降低时间复杂度 [ O(n)减少到O(log(n)) ] (int->long)
if(n % 2 == 1){
return x * myPow(x, n - 1);
}else{
//偶数情况, x^8 = (x^2)^4
return myPow(x * x, n / 2);
作者:edelweisskoko
链接:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/solution/jian-zhi-offer-16-shu-zhi-de-zheng-shu-c-rgqy/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
//public static void main(String[] args){
// myPow(2,3);
//}
public double myPow(double x, int n){
//一个特例,throw exception
if (x==0.0) {
throw new IllegalArgumentException();
}
//把n的值储存在long型变量里
long num = (long) n;
return calc(x,num);
}
public double calc(double x, long n) {
//base case, if n=0, myPow is 1, if n=1, myPow is x, if n=-1, myPow is 1/x.
//if n < 0, myPow is 1/x^n
//function: f(n) = f(n-1) ^ x
if (n == 0) {
return 1.0;
}
if(n == 1){
return x;
}
if (n < 0) {
// 1/x^|n|
return 1.0/calc(x,Math.abs(n));
}else if (n % 2 == 0) {
return calc(x * x , n / 2) ;
}else {
return calc(x * x , n / 2) * x ;
}
}
}
原题LeetCode地址
当然,本题还有多种解法,迭代法,快速幂解法,就不在这里一一赘述了。
(n&1) (判断奇偶)n为偶,值为0,n为奇,值为1.
n>>=1 相当于 n = n>>1, shifts all bits to the right (等于除以2)
例题2:
//import java.util.Arrays;
class Solution {
public int uniquePaths(int m, int n) {
//dp - dynamic programming 动态规划
//[m-1][n]的路线和到[m][n-1]的路线和汇总
//if(m==1||n==1)return 1;
//return uniquePaths(m, n-1)+uniquePaths(m-1,n);
//建一个数组储存数据
int[][] route = new int[m][n] ;
//Array completely filled with 0
// Fill each row with 0.
//for (int[] row : route){
// Arrays.fill(row, 0);
//}
//嵌套for循环
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
//base case是当i=0或j=0,对应[i][1]或者[1][j],此时只有一种方法,所以route[i][j]=1
if(i==0 || j==0){
route[i][j]=1;
}else{
//方程式关系
route[i][j]= route[i-1][j] + route[i][j-1];
}
}
}
//数组从route[0][0]开始,所以最后[m][n] 是 route[m-1][n-1]。
return route[m-1][n-1];
}
}
例题3:
例题4:
数楼梯 洛谷p1225
50%
100%
java高精度算法
import java.math.BigInteger;
Scanner sc=new Scanner(System.in);
大数操作
BigInteger a=sc.nextBigInteger();
BigInteger b=sc.nextBigInteger();
BigInteger d = new BigInteger("1");
BigInteger e = BigInteger.ONE;
BigInteger c=a.add(b);
BigInteger c=a.multiply(b);
BigInteger c=a.divide(b);
BigInteger c=a.subtract(b);
BigInteger c=a.max(b);
BigInteger c=a.divideAndRemainder(b);
import java.util.*;
import java.math.*;
//java自带高精尖,import java.math.BigInteger
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int N = in.nextInt();
//两个大数
// 1 ->1
// 2 ->1
BigInteger b1 = new BigInteger("1");
BigInteger b2 = new BigInteger("1");
//负数和0, return 0
if(N<1) {
System.out.println(0);
}else if(N<3){
//1,2 return 1,2
System.out.println(1);
}else{
//f(n)=f(n-1)+f(n-2)
for(int i = 1; i < N; i++) {
BigInteger temp = b2;
b2 = b1.add(b2);
b1 = temp;
}
System.out.println(b2);
}
//close scanner
in.close();
}
}