[Java算法] 递归(1)

练习一 : 汉诺塔

面试题 08.06. 汉诺塔问题 - 力扣(LeetCode)

java 复制代码
class Solution {
    public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
        dfs(A,B,C,A.size());
    }
        public void dfs(List<Integer> from, List<Integer> tmp, List<Integer> to, int n) {
        // 递归终止条件:只有1个圆盘,直接移动
        if (n == 1) {
            // 修正:remove(-1) → 移除列表最后一个元素(模拟栈顶,符合汉诺塔"从上到下取圆盘")
            to.add(from.remove(from.size() - 1));
            return;
        }

        // 步骤1:把n-1个圆盘从from移到tmp(以to为辅助)
        dfs(from, to, tmp, n - 1);
        // 步骤2:把第n个圆盘(最大的)从from移到to
        to.add(from.remove(from.size() - 1));
        // 步骤3:把n-1个圆盘从tmp移到to(以from为辅助)
        dfs(tmp, from, to, n - 1);
    }
}

细节问题 :

每次转移的圆盘应该是最上面的(A.size()-1)最小的哪个 , 而不是转移 0 下标的

练习二 : 合并两个有序链表

21. 合并两个有序链表 - 力扣(LeetCode)

java 复制代码
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null){
            return l2;
        }
        if(l2 == null){
            return l1;
        }
        if(l1.val<=l2.val){
            
            l1.next = mergeTwoLists(l1.next,l2);
           
            return l1;
        }else{
           
            l2.next = mergeTwoLists(l1,l2.next);
            
            return l2;
        }
        
    }
}

练习三 : 两两交换链表中的节点

24. 两两交换链表中的节点 - 力扣(LeetCode)

java 复制代码
/**
 * 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 swapPairs(ListNode head) {
    // 递归终止条件:空节点 或 只剩一个节点,无法交换,直接返回
    if(head == null || head.next == null){
        return head;
    }

    // 递归处理:从第三个节点开始,后面的所有节点先两两交换
    ListNode tmp = swapPairs(head.next.next);

    // 现在交换前两个节点:
    ListNode ret = head.next;   // 新头 = 原来的第二个节点
    ret.next = head;            // 第二个节点指向第一个节点(完成交换)
    head.next = tmp;            // 第一个节点指向后面已经交换好的部分

 
    return ret; // 返回新的头节点
}
}

算法原理 : 深度优先遍历(递归)

宏观角度看待 : 认为这个函数一定能完成排序工作

  • tmp = 后面全部换好的头
  • ret = 当前两个里的新头(第二个节点)
  • 换向 + 接尾巴
  • 必须 return 新头 ret,上层才能正常拼接

练习四 : 快速幂(Pow(x,n))

50. Pow(x, n) - 力扣(LeetCode)

java 复制代码
class Solution {
    public double myPow(double x, int n) {
        if((x-1) == 0){
            return 1;
        }
        if(n == -2147483648){  // 单独处理最小值
            n++;               // 先+1,变成 -2147483647(不会溢出)
            double res = 1.0 / pow(x, -n);
            return res / x;    // 再除一次x,补回刚才+1
        }
        if(n == 1){
            return x;
        }if(n<0){
            return 1.0/pow(x,(-1)*n);
        }
        if(n == 0){
            return 1.0;
        }
        if(n>0){
            return pow(x,n);
        }

        return 1;
    }
    public double pow(double x, int n){
        if(n == 1){
            return x;
        }
        double tmp = pow(x,n/2);
        return n%2 == 0?tmp*tmp:tmp*tmp*x;
    }
}

处理整型越界情况

当 -2147483648 去掉符号 2147483648 会超出 整型 2147483647 ; 我们就按 2147483647 次处理 , 最后再单独处理一次即可

实际代码完全不会报错,直接大胆传原负数 n 就行;最终结果靠底层两层递归兜底算出:n = 0 直接返回 1,n = -1 算出 1×1×X;再顺着递归一层层回溯相乘,最后外层统一用倒数规整负幂,全程避开数值越界

java 复制代码
class Solution 
{
 public double myPow(double x, int n) 
 {
 return n < 0 ? 1.0 / pow(x, n) : pow(x, n);
 }
 public double pow(double x, int n)
 {
 if(n == 0) return 1.0;
 double tmp = pow(x, n / 2);
 return n % 2 == 0 ? tmp * tmp : tmp * tmp * x;
 }
}

练习五 : 计算布尔二叉树的值

2331. 计算布尔二叉树的值 - 力扣(LeetCode)

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean evaluateTree(TreeNode root) {
        if(root.left == null){
            return root.val ==1?true:false;
        }
        boolean left = evaluateTree(root.left);
        boolean right = evaluateTree(root.right);
        return root.val == 2?(left||right):(left&&right);
    }
}

练习六 : 求根节点到叶子节点数组之和

129. 求根节点到叶节点数字之和 - 力扣(LeetCode)

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    int count = 0;  // 全局变量,记录最终总和

    public int sumNumbers(TreeNode root) {
        if (root == null) return 0; // 增加空树判断,更健壮
        dfs(root, 0);  // 从 0 开始更标准
        return count;
    }

    // DFS 递归:prev 表示当前路径已拼接的数字
    public void dfs(TreeNode root, int prev) {
        // 路径拼接公式
        int num = prev * 10 + root.val;

        // 到达叶子节点,累加结果
        if (root.left == null && root.right == null) {
            count += num;
            return;
        }

        // 递归左右子树
        if (root.left != null)  dfs(root.left, num);
        if (root.right != null) dfs(root.right, num);
    }
}
相关推荐
stolentime2 小时前
树套树+标记永久化:[POI 2006] TET-Tetris 3D&&SPOJ1741 TETRIS3D - Tetris 3D题解
c++·算法·线段树·树套树·标记永久化
XiYang-DING2 小时前
【LeetCode】链表 + 快慢指针找倒数结点 | 链表中倒数第k个结点
算法·leetcode·链表
LSL666_2 小时前
JVM面试题——垃圾回收GC
java·开发语言·jvm
白宇横流学长3 小时前
化妆刷生产管理系统分析与设计
java
洛_尘3 小时前
MiniMQ(单元测试报告)
java·测试
一轮弯弯的明月3 小时前
有序整数对个数-欧拉函数
java·算法·蓝桥杯·学习心得
lifewange3 小时前
Java 自动化测试参数化实现
java·数据库·sqlserver
码上农民3 小时前
Idea2025.3.3专业版安装和无限试用
java·ide·intellij-idea
CDN3603 小时前
CDN 回源异常、源站压力大?负载均衡与回源策略优化
java·运维·负载均衡