Unique path

题目原型:

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).

How many possible unique paths are there?


Above is a 3 x 7 grid. How many possible unique paths are there?

基本思路:

这种题目有三种解法,第一种是递归,第二种的动态规划,第三种是组合。我只想到了前两种。

(1)递归:

超时,代码略。比较简单。超时。

(2)动态规划

对于任意一点(x,y),要么是从(x,y)的左相邻点(x,y-1)过来,要么是从(x,y)的上相邻点(x-1,y)过来。如果用f(x,y)来表示robot走到点(x,y)时的走法,那么f(x,y)=f(x-1,y)+f(x,y-1)。其中,base条件是。当(x,y)位于最上面一行或者最左边一列时,由于robot要么向右走要么向下走,显然只能有1种走法,即f(x,y)=1 if(x==1 or y==0)。

	int uniquePaths(int m, int n)
	{
		int[][] num = new int[m][n];
		for(int i = 0;i<m;i++)
			num[i][0] = 1;
		for(int i = 0;i<n;i++)
			num[0][i] = 1;
		for(int i = 1;i<m;i++)
			for(int j = 1;j<n;j++)
			{
				num[i][j] = num[i-1][j]+num[i][j-1];
			}
		return num[m-1][n-1];
	}

其中网上网友给出了一种优化的动态规划,只需要O(min(m,n))大小的一个一维数组就可以了,这样能把动态规划的空间复杂度再优化一下。起算法如下:

// version 2 动态规划 bottom-up 空间复杂度由O(m*n)变化为O(min(m,n));
class Solution {
public:
    int uniquePaths(int m, int n) {
        int s=(m<n)?m:n;
        int l=(m>n)?m:n;
        int * arr= new int [s];
        for(int j=0;j<s;j++)
            arr[j]=1;
        for(int i=1;i<l;i++){
            for(int j=1;j<s;j++){
                arr[j]+=arr[j-1];
            }
        }
        return arr[s-1];
    }
};

******************************************************以下内容转自别人空间************************************************************************************

(3)排列组合

排列组合,挺巧妙的,正好在Cracking the Code Interview书中看到了这种解法。robot从第(1,1)点走到了第(m,n)点。它只能向右或者向下,不管它怎么走,它必然向右走了m-1步,向下走了n-1步。一共走了m-1+n-1步。而不同的走法,本质是向右或者向下构成的m-1+n-1长度的序列不同。走法的总数目,本质上是m-1+n-1个总步数中选出m-1个代表向右走的走法的个数,这个问题的另一种表述是,走法的总数目,本质上是m-1+n-1个总步数中选出n-1个代表向下走的走法的个数。这其实正是组合的小性质。

C(a+b, a)=C(a+b, b)
这样题目就转换为了一个数学计算了,求C(m-1+n-1, m-1)。

// version 3 组合数学角度求从m-1+n-1个数种选出m-1个数的组合的数目,即C(m-1+n-1, m-1)的数目。
class Solution {
public:
    unsigned long long  get_factorial(unsigned long long k){ //计算阶乘
        if(k==0)
            return 1;
        else
            return k*get_factorial(k-1);
    }
    
    int uniquePaths(int m, int n) {
        unsigned long long b=0; //防止溢出,用unsigned long long
        unsigned long long c=0;
        if(m<n){ //从m-1和n-1中选出一个较小的数,节省计算时间。因为C(m+n, n)和C(m+n, m)计算结果相等,所以可以这么简化。
            b=m-1;
            c=n-1;
        }else{
            b=n-1;
            c=m-1;
        }
        unsigned long long res=1;
        unsigned long long keep_b=b;
        while(b>0){
            res*=(b+c);
            b--;
        }
        res=res/get_factorial(keep_b);
        return (int)res;
    }

};




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值