算法复习-贪心、分治、回溯和动态规划原理与应用

文章探讨了回溯算法在排列(如全排列)和组合问题中的应用,涉及二叉树的路径生成,以及如何通过递归和剪枝减少重复计算,如在最长递增子序列和唯一路径问题中的优化方法。还介绍了动态规划和数组优化策略,如使用一维滚动数组来节省空间。
摘要由CSDN通过智能技术生成

回溯伪代码:

void backtracking(参数){
        if(终止条件){
            存放结果;
            return;
        }
        for(选择本层集合中元素(画成树,就是树子节点大小){
            处理节点;
            backtracking();
            回溯,撤销处理结果;
        }
    }

主要解决:排列(全排列),集合,组合问题 

例如:全排列 

输入:nums = [1,2,3]

输出:[1,2,3].[1,3,2].[2,1,3],[2,3,1].[3,1,2],[3,2,1]

 输出二叉树的所有路经

可以注意到有几个叶子节点,就有几条路径。从回溯的角度分析,得到路径ABD后怎么找第二条路径ABE,这里就要将D撤销(),然后再递归(

输入:root=[1,2,3,null,5]

输出:["1->2->5","1->3"]

 回溯部分:
 

private void dfs(TreeNode root, List<Integer> temp){
    if(root == null){
        return; //终止条件
    }
    temp.add(root.val){
    //如果是叶子节点记录
    if(root.left == null && root.right == null){
        ans.add(getPashString(temp));
    }
    dfs(root.left,temp);
    def(root.right, temp);
    temp.remove(temp.size()-1);//撤销
    }
动态规划

最简单的例子:找出最长的递增的子序列长度(3)

输入:nums = [1,5,2,4,3]

输出:[1,2,4],[1,2,3]

         观察遍历树可以发现有许多重复计算,如在遍历1,2,4的时候就已经计算过“从4开始的最大子序列的长度”。后面遍历去1,4时已经知道不是最长序列了(要经过2)有重复的计算——所以可以在第一次计算的时候将结果保存,之后遍历相同的节点就不需要重复计算(核心:递归+剪枝

例题:统计路经之和

//只使用递归实现
public class uniquePaths{
    public void uniquePath(int m, int n){
        return search(m , n);
        }
    public int search(int  m, int n){
        if(m == 1|| n == 1){
            return 1;
        }
        return search(m-1, n) + search(m, n+1);
    }
}

使用二维数组优化递归

 

 实现

 

public int uniquePaths(int m, int n){
    int[][] f = new int[m][n];
    f[0][0] = 1;
    for (int i=0; i<m; i++){
        for(int j = 0; j<n; j++){
            if(i>0 && j>0){
                f[i][j] = f[i-1][j] + f[i][j-1];
            }else if(i > 0){
                f[i][j] = f[i-1][j];
            }else if(j> 0){
                f[i][j] = f[i][j - 1];
            }
        }
     }
    return f[m-1][n-1];
}

滚动数组:用一维代替二维数组

缓存空间用二维数组比较占空间

得到:

 

 

public int uniquePaths(int m, int n) {
     int[] dp = new int[n];
     Arrays.fill(dp, 1);
     for(int i = 1; i < m; ++i) {
         for(int j = 1; j < n; ++j) {
         //等式右边的 dp[j]是上一次计算后的,加上左边的dp[j-1]即为当前结果
             dp[j] = dp[j] + dp[j - 1];
         }
     }
        return dp[n - 1];
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值