力扣2-递归算法—第1次整理

1.剑指 Offer 10- I. 斐波那契数列(递归&循环)

  • 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。
    答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

1.解题思路(递归)——但是会超出时间限制

  • 1.斐波那契数列是,从第2项开始,后一项是前两项的加和
    f(n) = f(n-1) + f(n-2) ; f(0)=0,f(1)=1,n>1.
class Solution {
    public int fib(int n) {
        if (n==0) return 0;
        if (n==1) return 1;
        return (fib(n-1)+fib(n-2))%1000000007;
    }
}

2.解题思路(循环)

  • 1.因为当前项是相邻前2项的加和,所以可以维持2个实时更新的变量,prepre, pre;
class Solution {
    public int fib(int n) {
        0.特殊值处理
        if (n==0) return 0;
        if (n==1) return 1;
        int prepre = 0,pre = 1;
        int res=0;
		1.开启循环
        for (int i = 2; i <= n ; i++) {
            res = (prepre + pre)%1000000007;
            2个变量更新
            prepre = pre;
            pre    = res;
        }
        2.返回值
        return res;
    }
}

2.剑指 Offer 10- II. 青蛙跳台阶问题(动态规划)

青蛙跳台阶问题
在这里插入图片描述

1.解题思路

  • 1.青蛙跳上n级台阶,那么青蛙跳最后一步有两种跳法,跳1级 或者 跳2级;
  • 2.青蛙最后一步跳1级,则前边的n-1级有 f(n-1) 种跳法;
  • 3.青蛙最后一步跳2级,则前边的n-2级有 f(n-2) 种跳法;
  • 4.所以f(n) = f(n-1) + f(n-2) ,又回到了斐波那契数列问题。

2.递归与循环

1.递归解法会超时,因为他会重复求某些解
2.循环解法 则跟上一题思路差不多。

3.剑指 Offer 16. 数值的整数次方

剑指 Offer 16. 数值的整数次方

  • 实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。

1.解题思路

1.1.递归思路(会超时)
  • 1.考虑递归,次方不就是 乘多少个x,但是可能会有超时的问题;
  • 2.优化递归,当次方是2、3、4等数的整数倍时,可以考虑一次性就乘2个x、3个x、4个x。
class Solution {
    public double myPow(double x, int n) {
        if (n==0) return 1;
        if (x==0) return 0;
        0.处理负数的情况
        if (n<0)
            1.为什么这里要 单独乘个x?
            return 1/(myPow(x,-n-1)*x);
        2.正数的情况
        return n%2==0? myPow(x*x,n/2) : myPow(x*x,n/2)*x;
    }
}
1.2.循环思路(不优化 会超时)
  • 1.优化前
class Solution {
    public double myPow(double x, int n) {
        0.特殊情况处理
        if (x==0 || n==1)  return x;
        if (n==0)  return 1;
        0.5 到这里说明n ≠ 0
        double res = 1;
        1.处理负值
        int m = n<0? -1*n :n;
        for (int i = 0; i < m; i++) {
            res *= x;
        }
        2.处理负值的情况
        return n<0? 1/res :res;
    }
}
  • 2.优化后(for (int i = n; i!=0; i/=2 ,x*=x) )这部分看不懂
class Solution {
    public double myPow(double x, int n) {
        0.特殊情况处理
        if (x==0 || n==1)  return x;
        if (n==0)  return 1;
        到这里说明n!=0
        double res = 1;
        1.这里看不懂!!!!
        for (int i = n; i!=0; i/=2 ,x*=x) {
            if (i%2!=0)
                res *=x;
        }
        2.处理负值的情况
        return n<0? 1/res :res;
    }
}

21. 合并两个有序链表

21. 合并两个有序链表

  • 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
    在这里插入图片描述

1.解题思路

1.循环解法
  • 1.新建一个暂时性队首节点prehead,一个动态临时节点prev,循环遍历两条链表L1、L2 的队首节点值,取小的放入即可。
class Solution5 {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
      0.新链表的暂时性队首节点prehead
        ListNode prehead = new ListNode(-1);
      1.动态变化的临时性节点prev
        ListNode prev = prehead;
      2.当两个链表均不为空时,才能进行节点值比较
         并取出较小的节点值放入新链表的下一个
        while (l1 != null && l2 != null) {
            if (l1.val <= l2.val) {
                prev.next = l1;
                l1 = l1.next;
            } else {
                prev.next = l2;
                l2 = l2.next;
            }
            prev = prev.next;
        }
      3.合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
        prev.next = l1 == null ? l2 : l1;
      4.要返回暂时性队首prehead的下一个节点
        return prehead.next;
    }
}
2.递归解法
  • 1.直接把它当成一个功能完备的算法,在这里是它可以把2个升链表给合成1个升序链表;
  • 2.当L1.val<L2.val时,说明此时的L1是合并完后总链表的头节点,那么把L1.next 和 L2送入递归,
    递归完,就直接返回L1即可。
  • 3.当L2.val<=L1.val时,说明此时的L2是合并后的总链表的头节点,那么把L2.next和L1送人递归,
    递归结束,就直接返回L2即可。

	★★★★★:其实步骤2、3,就是一步步找出各子部分的头结点,然后再连成串!

  • 4.特殊情况的处理,在考虑进来即可。
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        0.特殊情况的处理
        if (l1==null)
            return l2;
        0.特殊情况的处理
        else if (l2==null)
            return l1;
        1.当l1是头节点时
        else if (l1.val<l2.val){
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        2.当l2是头结点时。
        }else{
            l2.next = mergeTwoLists(l1,l2.next);
            return l2;
        }
    }
}

4. 两数相加(腾讯50题)

两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
在这里插入图片描述

1.解题思路

  • 1.直接把该方法当成“功能完善的方法”;新建当前递归的头节点head,每个递归都会新建一个head,待递归结束时,所有头节点就会串起来了。
  • 2.情况分析:
    1. 当前位,2数相加sum <10, 那直接相加即可,不需考虑进位问题;
    2. 当前位,2数相加sum>=10,那就取余数存入当前位,可知(sum/10)只能是1,可以把(sum/10=0?)作为一种判断条件,不为0,则向下进位 1.
    3. 假设一直以L1.next.val,承接进位,就要考虑L1.next是否为空的问题,为空则new出新节点,并存入进位1即可。
  • 3.特殊情况的处理:
    1.L1、L2都是null,很简单,直接返回null;
    2.L1为null,L2不为null,但是L2.val>=10,此时还需要继续处理,需要new一个新的L1,只不过节点值为0。
    3.L1为null,L2不为null,且L2.val<10,此时直接返回L2即可。
    4.L2为null的情况与L1相同,不再赘述。
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    	0.特殊情况处理
        if (l1==null && l2==null) return null;
        0.1.说明l2不需要进位处理,直接return
        if (l1==null && l2.val<10) return l2;
        0.2.说明l2的节点值>=10,需要处理进位
        此时l1虽然为空,但还是要参与接下来的处理,所以new出新的l1,节点值设为0
        if (l1==null) l1=new ListNode(0);
		0.3.这种与2相同,不再赘述
        if (l2==null && l1.val<10) return l1;
        if (l2==null) l2=new ListNode(0);
 
        1. 建立头节点,取%10余数 作为新的头节点的值
        int num = (l1.val+ l2.val)%10;
        ListNode head = new ListNode(num);
        2.当前节点需要进位时
        if ((l1.val+ l2.val)/10!=0) {
        	2.1.考虑l1.next是否为空的问题
            if (l1.next != null)
                l1.next.val = l1.next.val + 1;
            else
                l1.next = new ListNode(1);
        }
        3.调用递归
        head.next = addTwoNumbers(l1.next, l2.next);
        return head;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值