动态规划

动态规划问题记住:一般用递归分析(从上往下分析),然后用循环实现(从下往上计算)
动态规划类问题,我们一定可以找出一个递推式,比如
青蛙跳台阶:一只青蛙一次可跳1级台阶,也可以跳2级台阶,那么青蛙跳上n级台阶有多少种跳法。
从上往下分析:在第n级台阶的青蛙,上一步可以是从n-1级跳过来的,也可以是由n-2级跳过来的,如果记f(n)为青蛙到n级台阶的跳法,那么有f(n)=f(n-1)+f(n-2)
这是从上往下分析得到的递推式,我们现在如果直接写代码用递归就可以简洁明了的实现

static int f(int n)
{
	if(n==0||n==1) return 1;
	return f(n-1)+f(n-2);
}

这道题其实就是斐波那契数列的递推式。
它用递归实现存在一个什么问题?我们举个例子
比如求 f(10),我们要递归求 f(9) 和 f(8),而求f(9) 再次递归求 f(8)和 f(7),f(8)是重复计算的子问题。
也就是说我们在递归计算的过程中存在很多重复子问题的重复计算,时间效率不高。本身递归就比循环的效率低,因为递归调用需要保存参数、返回地址、临时变量,数据压入弹出栈都是需要时间的。再加之,子问题的重复计算,效率将会更低。
所以对于 “ 子问题之间重叠更小子问题 ” 的情况,我们用自下而上的循环解决问题将会更好。
上面的递归对应的循环解法为:

static int f(int n)
{
	if(n==0||n==1) return 1;
	int f1=1;
	int f2=1;
	int fn=0;
	for(int i=2;i<=n;i++)
	{
		fn=f2+f1;
		f1=f2;
		f2=fn;
	}
	return fn;
}

面试题46:把数字翻译成字符串
题目:输入一个数字,按如下规则翻译成字符串:0翻译成"a",1翻译成"b",2翻译成"c",3翻译成"d",… ,25翻译成"z"。一个数可能有多种翻译,例如:12258,可以翻译成"bccfi",“bwfi”,“bczi”,“mcfi”,”mzi"。
分析:12258 = 1 + 2258 或者 12 + 258,很明显这可以归纳出递归式。
f(i)=f(i+1)+check(i,i+1)*f(i-2)
check(i,i+1)为判断第i位和第i+1位拼在一起的数字是否在10-25内。
f(i)代表从第i位开始翻译可以翻译出的数目,那它应该等于,第i位自己翻译然后拼在f(i-1)前面(这个数目就是f(i-1)),以及第i位和第i+1位合并翻译然后拼在f(i+2)前面。
但是这道题如果用递归实现,存在子问题的重复:因为12258 = 1 + 2258 或者 12 + 258,而 2258 = 2+258 ,258就是重复翻译的部分。
分析时我们从左往右递归分析,计算时可以从右向左循环计算。

import java.util.Scanner;
public class Main
{
 	public static void main(String args[])
 	{
  		Scanner sc = new Scanner(System.in);
  		int num = sc.nextInt();
  		sc.close();
  		System.out.println(f(num));
 	}
 	static int f(int num)
 	{
  		if(num<0)
   		return -1;
  		return f(String.valueOf(num));
 	}
 	static int f(String num)
 	{
  		int len = num.length();
  		int[] counts = new int[len]; //counts[i]相当于上面分析中的f(i)
  		int count=0;
  		for(int i=len-1;i>=0;i--)
  		{
   			count=0;
   			if(i<len-1)
    				count=counts[i+1]; //第i位单独翻译,数目即为f(i+1)
   			else
    				count=1;
   			if(i<len-1)
   			{
    				int n1=num.charAt(i)-'0';
    				int n2=num.charAt(i+1)-'0';
    				int n=n1*10+n2;
    				if(n>=10&&n<=25)
    				{
     					if(i<len-2) count+=counts[i+2]; //第i位和第i+1位合并翻译,数目为f(i+2)
     					else count++;
    				}
   			}
   			counts[i]=count;
  		}
  		return counts[0];
 	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值