05 | 递归(上):泛化数学归纳,如何将复杂问题简单化?
05 | 递归(上):泛化数学归纳,如何将复杂问题简单化?
讲述:黄申
时长09:12大小8.41M
如何在限定总和的情况下,求所有可能的加和方式?
如何把复杂的问题简单化?
小结
思考题
赞 30
提建议
精选留言(172)
- 黄申置顶2018-12-20由于暂时无法追加回复,我这里再回复一下网友debugtalk 我看了Python的实现,果然很简介👍 奖金的题目没问题。整数的因子分解有点小瑕疵,少了一些可能。比如,输入8,少了 [1, 2, 2, 2] [1, 2, 4] [1, 4, 2] [2, 1, 2, 2]展开18
- 杨景胜2018-12-19从递归的两个原则到代码实现有点跳跃, 想了半天还是没想明白这个代码的逻辑啊~共 2 条评论26
- 李尧2018-12-19思考题:请大神帮忙看下,输出少了个 [1,8] 输出:[2, 2, 2, 1] [2, 4, 1][4, 2, 1][8, 1] import java.util.ArrayList; /** * @Auther: yli * @Date: 2018/12/19 17:19 * @Description: */ public class Iteration { public static void recursion(long total, ArrayList<Long> result){ if (total == 1){ result.add(1L); System.out.println(result); return; }else { for(long i = 2; i <= total; i ++){ ArrayList<Long> newList = (ArrayList<Long>)(result.clone()); newList.add(Long.valueOf(i)); if(total%i !=0){ continue; } recursion(total/i, newList); } } } public static void main(String[] args){ long total = 8; recursion(total, new ArrayList<Long>()); } }展开
作者回复: 循环的时候不能少了1,可以在结果中判断是否已经涵盖1,我稍微修改了一下 public static void recursion(long total, ArrayList<Long> result) { if (total == 1) { if (!result.contains(1L)) result.add(1L); System.out.println(result); return; } else { for (long i = 1; i <= total; i++) { if ((i == 1) && result.contains(1L)) continue; ArrayList<Long> newList = (ArrayList<Long>) (result.clone()); newList.add(Long.valueOf(i)); if (total % i != 0) { continue; } recursion(total / i, newList); } } }
共 6 条评论13 - debugtalk2018-12-19Python 实现赏金问题:https://github.com/debugtalk/geektime-notes/blob/master/programmers-mathematics/chapter5.md Python 实现思考题:https://github.com/debugtalk/geektime-notes/blob/master/programmers-mathematics/chapter5.py
作者回复: 很棒 我稍后sync下来看
共 2 条评论12 - 文刂 氵共 超2018-12-19整数分解 - C++代码 #include <vector> #include <iostream> #include <algorithm> using namespace std; // 输出函数 void PrintResult(vector<int> &Result) { for (size_t i = 0; i < Result.size(); ++i) { cout << Result[i] << " "; } cout << endl; } //数组中是否存在某值 bool IsExit(vector<int> &Result, int value) { vector<int>::iterator result = std::find(Result.begin(), Result.end(), value); if (result == Result.end()) { return false; } else { return true; } } //整数分解 void RecursionAlgo(int Num, vector<int> &Result) { if (Num == 1) { PrintResult(Result); return; } for (int i = 1; i <= Num; ++i) { //判断1是否在解中 if (IsExit(Result, 1)) { if (i == 1) { continue; } } if (Num%i == 0) { vector<int> newResult = Result; newResult.push_back(i); RecursionAlgo(Num/i, newResult); } } } int _tmain(int argc, _TCHAR* argv[]) { int Totalmoney = 10; vector<int> Result; RecursionAlgo(Totalmoney, Result); return 0; }展开
作者回复: 回答很棒,下次可以将运行结果也贴出来👍
9 - 罗耀龙@坐忘2020-03-28茶艺师学编程 一般人说到泡茶,大多数会条件反射般的 1、拿出茶叶 2、放进杯子 3、加入开水 4、等一下,喝 这样从前往后按步骤来的思维方法,正是人类“无师自通”的递推思维。 而经过训练的茶艺师会这么做 1、先看要泡什么茶 2、根据要什么茶来选定用什么器皿,假如要泡龙井绿茶,那就拿出直身玻璃杯 3、这时怎么泡也决定了,就是先把玻璃杯温起来,然后放入龙井,先加一点水润一润,再把水加满,其中水温不能太烫。 4、等一下,喝 想这样根据结果倒逼步骤,从上往下的顶层设计,很明显以上面的方法顺序相反。同学们看到这肯定会得意的说,“你们(茶艺师)在不经意间就使用了递归思想。”展开8
- 方得始终2018-12-29参考老师和其他同学的留言, 下面是Pythoni实现的思考题, 应该是个较为简洁的版本. import copy def prod_factors(num, result=[]): if num == 1: print('x'.join([str(_) for _ in result])) if 1 not in result: result.append(1) print('x'.join([str(_) for _ in result])) elif num < 0: return else: for i in range(1, num+1): if (i == 1 and i not in result) or (i !=1 and num % i == 0): newresult = copy.copy(result) newresult.append(i) prod_factors(num/i, newresult) prod_factors(8) 1x2x2x2 1x2x4 1x4x2 1x8 2x1x2x2 2x1x4 2x2x1x2 2x2x2 2x2x2x1 2x4 2x4x1 4x1x2 4x2 4x2x1 8 8x1展开
作者回复: 同时考虑了1出现和不出现的情况 👍
共 6 条评论7 - 松原2018-12-19黄老师,这句“递归和循环其实都是迭代法的实现”我不太理解。 如果递归和循环都属于迭代法,那么就是说递归是从属于迭代法的。而我所理解的迭代法的核心是从1到n的递推,而递归是从n到1的逐步求解的过程,两者应该是并列的关系。希望老师能解答我的这个困惑。
作者回复: 确实两者的递推方向是不一样的,不过递归在计算机的实现中,是使用的函数调用,在满足条件后,函数开始逐级返回,这时候又是正向递推了,所以我觉得这也是从1到n
6 - hallon2018-12-21思考题,用js实现如下: function mul(totalReward, result) { //i从自身开始循环到1,每次递减1 for(var i=totalReward; i>0; i--) { if(totalReward % i == 0) {//能整除i var newResult = result.concat(); newResult.push(i); if(i == totalReward) {//i为自身的情况,结果就是[totalReward,1] newResult.push(1); console.log(newResult); } else if(i == 1) {//i为1的情况,结果就是[1,totalReward] newResult.push(totalReward); console.log(newResult); }else {//除以i之后,继续分解 mul(totalReward/i, newResult); } } } } 测试:数字6和8 var b = []; mul(6, b); mul(8, b); 结果如下: [ 6, 1 ] [ 3, 2, 1 ] [ 3, 1, 2 ] [ 2, 3, 1 ] [ 2, 1, 3 ] [ 1, 6 ] [ 8, 1 ] [ 4, 2, 1 ] [ 4, 1, 2 ] [ 2, 4, 1 ] [ 2, 2, 2, 1 ] [ 2, 2, 1, 2 ] [ 2, 1, 4 ] [ 1, 8 ]展开5
- Sawyer2019-03-12老师好,我实现了一个算法,但是没有打印出来1的情况。 还有个问题就是,如果使用老师的示例输入8,结果既有 2x4,又有 4x2 这不是重复了吗? static void getFactorization(long product, ArrayList<Long> result) { for (int i = 2; i <= product / 2; i++) { if (0 == product % i) { ArrayList<Long> newResult = (ArrayList<Long>) result.clone(); newResult.add((long) i); getFactorization(product / i, newResult); newResult.add(product / i); System.out.println(newResult); } } }展开
作者回复: 这里作为教学案例,可以遍历所有情况,包括4x2和2x4。至于1,需要特殊处理一下,你可以思考看看,或者看看之前读者的留言
3 - debugtalk2018-12-20感谢 Sean 的指正,之前整数因子分解的解答的确存在问题,没有完整考虑整数 1 在各种位置的情况。 现已更正:https://github.com/debugtalk/geektime-notes/blob/master/programmers-mathematics/chapter5.py3
- 杨景胜2018-12-19//因数分解 public static void getMultiFactors(long multi,ArrayList<Long> result){ if (multi == 1){ result.add(multi); System.out.println(result); }else{ for (long i = 2; i <= multi; i++) { if(multi % i == 0){ ArrayList<Long> newResult = (ArrayList<Long>) result.clone(); newResult.add(i); getMultiFactors(multi / i,newResult); } } } }展开
作者回复: 如果循环从2开始,可能会漏掉一些情况,请参考为我给另一位网友李尧的回复
3 - 悬炫2019-01-28JavaScript的实现: 赏金问题: /** * * @description 赏金问题 * @param {number} totalReward 奖赏总金额 * @param {array} result 保存当前的解 * @param {array} rewards 可供选择的面额 * @returns void */ function get(totalReward, result=[],rewards = [1, 2, 5, 10]) { // 当 totalReward = 0 时,证明它是满足条件的解,结束嵌套调用,输出解 if (totalReward === 0) { console.log(result.toString()); // 当 totalReward < 0 时,证明它不是满足条件的解,不输出 } else if(totalReward<0) { return; } else { for (let index = 0; index < rewards.length; index++) { let newResult =[...result];// 由于有 4 种情况,需要 clone 当前的解并传入被调用的函数 newResult.push(rewards[index]);// 记录当前的选择,解决一点问题 get(totalReward - rewards[index], newResult);// 剩下的问题,留给嵌套调用去解决 } } }展开2
- Youngggg2018-12-25import copy def get(num, result=[]): sum = 1 for index in result: sum = sum * index if sum == num: print(result) if 1 not in result: result.append(1) print(result) return elif sum > num: return else: i=1 while i<=num: if num%i != 0: i = i+1 continue if i == 1 & 1 in result: i = i+1 continue new_result = copy.copy(result) new_result.append(i) i = i+1 get(num, new_result) get(8, []) [1, 2, 2, 2] [1, 2, 4] [1, 4, 2] [1, 8] [2, 1, 2, 2] [2, 1, 4] [2, 2, 1, 2] [2, 2, 2] [2, 2, 2, 1] [2, 4] [2, 4, 1] [4, 1, 2] [4, 2] [4, 2, 1] [8] [8, 1]展开2
- icy2018-12-24# -*- coding: utf-8 -*- """ Created on Mon Dec 24 14:30:38 2018 @author: icytanz """ import copy def get_mul_factor(num,result=[]): if(num==1): total=copy.copy(result) if 1 not in total: total.append(1) print(total) return elif(num<1): return else: n=list(range(num+1)) n.reverse() if 1 in result: m=range(len(n)-2) else: m=range(len(n)-1) for i in m: new_result=copy.copy(result) if num%n[i]==0: new_result.append(n[i]) get_mul_factor(num//n[i],new_result) if __name__=='__main__': get_mul_factor(2) #[2, 1] #[1, 2] get_mul_factor(1) #[1] get_mul_factor(4) #[4, 1] #[2, 2, 1] #[2, 1, 2] #[1, 4] #[1, 2, 2] get_mul_factor(6) #[6, 1] #[3, 2, 1] #[3, 1, 2] #[2, 3, 1] #[2, 1, 3] #[1, 6] #[1, 3, 2] #[1, 2, 3] get_mul_factor(8) #[8, 1] #[4, 2, 1] #[4, 1, 2] #[2, 4, 1] #[2, 2, 2, 1] #[2, 2, 1, 2] #[2, 1, 4] #[2, 1, 2, 2] #[1, 8] #[1, 4, 2] #[1, 2, 4] #[1, 2, 2, 2]展开2
- 郑晨Cc2018-12-20package 二进制; import java.util.ArrayList; public class Lesson5Test { public int counter = 0; public void chosen(int num,ArrayList list){ if(null==list){ list = new ArrayList(); list.add(1); list.add(num); } if(num==1){ //递归终止 return; } for(int i=1;i<=num;i++ ){ if(i==1){ System.out.println(list); counter++; continue; } if(i==num){ list.add(1); list.remove(0); System.out.println(list); counter++; continue; } if(num%i==0){ int a = num/i; ArrayList list2 = new ArrayList(list); list2.remove(list.size()-1); list2.add(i); list2.add(a); chosen(num/i,list2); } } } public static void main(String[] args){ Lesson5Test too = new Lesson5Test(); too.chosen(8, null); System.out.println("总数:"+too.counter); } } 控制台输出: [1, 8] [1, 2, 4] [1, 2, 2, 2] [2, 2, 2, 1] [2, 4, 1] [1, 4, 2] [4, 2, 1] [8, 1] 总数:8展开2
- miracle2018-12-19我来答下吧,案例中的n代表已经迭代的次数,在这个案例中,限制了每轮迭代只有四种选择2
- cocu2018-12-19这个案例中的n到底是什么,是奖励总金额,还是取的纸币数?
作者回复: 这里我统一回答一下,是当前迭代的次数,也就是取的纸币数量
2 - Jtay-dlz2020-04-19def get(t, result): r = [5,2,1] if t==0: print(result) return elif t<0: return for i in r: get(t-i, result+str(i)+' ') get(5, '') ----------------5 2 2 1 2 1 2 2 1 1 1 1 2 2 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 1展开1
- Noah●^●2019-12-22#include <iostream> #include <vector> using namespace std; const int N = 4; int coins[N] = {1, 2, 5, 10}; int n; vector<int> closen; int count; void dfs(int u) { if(u > n) return; if(u == n) { for(int i = 0; i < closen.size(); i++) { if(i > 0) printf(" "); printf("%d", closen[i]); } puts(""); count++; return; } for(int i = 0; i < N; i++) { closen.push_back(coins[i]); u += coins[i]; dfs(u); closen.pop_back(); u -= coins[i]; } return; } int main(void) { scanf("%d", &n); dfs(0); printf("一共有: %d 种方案\n",count); return 0; }展开1