动态规划(dynamic programming)

动态规划具有两个属性,如果一个问题具有这两个属性,说明这个问题可以用动态规划来做。

(1)子问题重叠
(2)最优子结构

本文将用来讨论第一个属性。

动态规划主要用于需要反复解决相同子问题的情况。在动态规划中,子问题的计算解决方案存储在表中,因此不必重新计算这些问题。因此,在没有常见(重叠)子问题时,动态编程就没有用。

案例一:Fibonacci Numbers

方法一:递归

	public int fib(int n)
	{
		if(n<=1)
			return n;
		return fib(n-1)+fib(n-2);
	}

缺点:我们根据画出递归树可以很明显看出,有许多重复计算的分支。于是我们应用动态规划,。我们使用表来将我们已经计算过的存储起来。

动态规划中用表存储子问题一般有两种方法:

  • 记忆法,自上而下,按需填表
  • 制表法,自下而上,从下面的条目开始,一个一个向上填充。

方法二:记忆法存储重叠子结构


	public int fib2(int n)
	{
	//声明一个数组用于存放已经计算过的子问题
		if(lookup[n]==-1)
		{
		//如果这个子问题没有计算过,则和递归中处理相似,只是值不是直接返回,而是存入数组中,
			if(n<=1)
				lookup[n]=n;
			lookup[n]=fib2(n-1)+fib2(n-2);
		}
		//如果这个数组计算过,则直接返回计算过的值
		return lookup[n];
	}

方法三:利用制表法存储已经解决的子问题

	{
	//声明一个表格长度为n+1的数组,用于存储
		int[] table=new int[n+1];
		//由下到上,前两个条目先明确
		table[0]=0;
		table[1]=1;
		//通过循环迭代,计算出传入的值 。
		for(int i=2;i<=n;i++)
		{
			table[i]=table[i-1]+table[i-2];
		}
		return table[n];
		
	}

案例二:Ugly Numbers

Ugly Numbers 是只包含质因子2、3和5的数。

怎么获得ugly numbers?
首先除2,直到不能整除为止,然后除5到不能整除为止,然后除3直到不能整除为止。最终判断剩余的数字是否为1,如果是1则为丑数,否则不是丑数。

题目:寻找出第n个丑数。

方法一:逐一遍历

public int maxdivide(int a,int b)
	{
		//a 除以b的最大可乘幂
		while(a%b==0)
			a=a/b;
		return a;
	}
	public boolean isUgly(int num)
	{
	//判断一个数是不是丑数
		num=maxdivide(num,2);
		num=maxdivide(num,3);
		num=maxdivide(num,5);
		
		return num==1;
	}
	public int uglyNumbers(int n)
	{
	//在第n个丑数前面的整数每个都进行是否是丑数的判断。
		int count=1;
		int i=1;
		while(count<n)
		{
			i++;
			if(isUgly(i))
				count++;
		}
		return i;
		
	}

方法二:动态规划法
具有重叠子问题,我们把重叠的子问题的结果存储下来,利用制表法,由下至上。

因为每个丑数都能被2,3,5除,所以我们可以把丑数表示为下列三种群体:
(1) 1×2, 2×2, 3×2, 4×2, 5×2, …
(2) 1×3, 2×3, 3×3, 4×3, 5×3, …
(3) 1×5, 2×5, 3×5, 4×5, 5×5, …
将上述群体存放到数组中,利用三个指针i2,i3,i5:
第一个是1,第二个通过在三个群体中找到最小值,并将其存入,然后将其指针下移,重复上述步骤。



public int UglyNumbers(int n)
	{
	//声明一个数组用于存放丑数
		int[] ugly_num=new int[n];
		int i2=0,i3=0,i5=0;
	//自下而上,第一个是1,
		ugly_num[0]=1;
		
		int next_mulitple_of_2=2;
		int next_mulitple_of_3=3;
		int next_mulitple_of_5=5;
		
		for(int i=1;i<n;i++)
		{
		
			ugly_num[i]=Math.min(next_mulitple_of_2, Math.min(next_mulitple_of_3, next_mulitple_of_5));
			
			if(ugly_num[i]==next_mulitple_of_2)
			{
				i2++;
				next_mulitple_of_2=2*ugly_num[i2];
			}
			if(ugly_num[i]==next_mulitple_of_3)
			{
				i3++;
				next_mulitple_of_3=3*ugly_num[i3];
			}
			if(ugly_num[i]==next_mulitple_of_5)
			{
				i5++;
				next_mulitple_of_5=5*ugly_num[i5];
			}
			
		}
		return ugly_num[n-1];
	}

发布了49 篇原创文章 · 获赞 2 · 访问量 878

猜你喜欢

转载自blog.csdn.net/qq_43720551/article/details/104922210