简单编程题目连载(五)——找零钱

来源:互联网 发布:java框架面试题及答案 编辑:程序博客网 时间:2024/05/22 01:28

接着上一篇的经典动态规划题目来说。

上一篇的解题方法为暴力求解法,暴力求解法之所以称之为暴力求解法,是因为其中存在着大量的冗余,比如:

对于penny数组{5,10,25,1},目标金额为1000,来说,当使用0张5元,1张10元,进行接下来的递归计算,调用的函数为:res(penny,2,990)。而当使用2张5元,0张10元,进行接下来的递归计算,调用的函数为:res(penny,2,990)。

原解法中,递归计算的数组penny是不变的,每次改变的是递归函数的index和aim。而上述例子表明存在大量index和aim相同的递归函数,也就是说,进行了大量的重复计算。所以优化的第一个思路就是将这些重复计算记录下来,下次遇到之前计算过的结果,直接查找调用。这就是记忆搜索法。这是一个空间换时间的方法。

接下来看代码:

public int countType(int[] penny,int n,int aim){    if(penny == null || n <= 0 || aim <= 0){        return 0;    }    //声明一个二维数组  用来存重复的res(penny,index,aim);的结果    int[][] map = new int[n+1][aim+1];    res(penny,index,aim,map);}public int res(int[] penny,int index,int aim,int[][] map){    int result = 0;    //说明有值且不为0    if(map[index][aim] > 0){        return map[index][aim];    }else if(map[index][aim] == -1){        return 0;    }else{//这个意思就是第一次遇到这个index和aim的组合        result = aim == 0 ? 1 : 0;        for(int i = 0;index < penny.length && penny[index]*i <= aim && aim > 0;i++){            result += res(penny,index+1,aim-penny[index]*i,map);        }        //设置一个-1的目的是为了 区分 递归结果为0 的那些结果与数组初始化结果也为零冲突        map[index][aim] = result == 0 ? -1 : result;        return result;    }}

以上为找零钱题目的记忆搜索法求解过程。

0 0