数学的力量(四)

一个月没写博客,都是被论文整的,期间还参加了个Topcoder的马拉松,排在十几名,也没拿到奖金,蛋疼的很。

本篇博客还是从组合数学的角度出发,继续探讨数学在编程中的力量。

问题描述:

给定N个不重复的整数和一个正整数A,使在N中无放回的选出4个数,使得该四个数之和等于A,求有多少种选法。

1、O(n^4)

首先给出编程方法与思路最简单,但执行时间最长的方法。既然要从N个数选取4个,就遍历其所有组合就好了,需要遍历的总数为C(N,4),当N趋近正无穷时,这个组合数和N^4是同阶无穷大,所以需要的时间复杂度为O(N^4)。

当然这种最原始的方法只能自己想想,如果刷比赛题目或者去面试把这个当作答案估计要被人喷死。

2、O(n^3)

再稍微仔细分析一下这个问题,我们可以发现,这么一个事实。

取4个数的实质是判断集合中哪4个数需要取,但实际上我们不需要取4个数,而只取三个数就够了。取出三个数后,只需要判断A与这三个数的差是否还在集合中,若在,则是一种可行的组合,若不在,则不可能找到可行的组合。

所以为了实现O(1)的查找,在数据结构上可选择哈希表,先使用O(n)的时间构造一个哈希表,然后遍历所有的3-组合数,即可得到答案。

值得注意注意的是,这样做不能保证同一个解只选取了一次,举例来说,假定N个数为1、2、3、4、5,此时有A=10,当求三的组合数的时候,若选取的是1、2、3,则会找到一个可行的组合;若选取2、3、4,则也会找到一个可行的组合,而这属于同一组合。

因此还需要使用一个Set来存放解,以此来保证每一个解的唯一性。

3、O(n^2)

使用一些数据结构上的技巧,通过空间换时间的方法,感觉应该也是可以达到N^2时间复杂度的,比如使用一个更大的hashtable来存储所有2-组合的和,在此基础上通过负责的机制与分析或许可以得到n^2时间复杂度的方法,但笔者在这里说的是使用一种数学方法构造时间复杂度为n^2的算法。

设n个不同的数为a1,a2,a3.....an,则构造函数f(x)=(1+x^a1)(1+x^a2)(1+x^a3)...(1+x^an)。易知展开后x次数为A项的系数就是所要求的结果。

剩下的工作就很简单了,编个程序展开这个多项式,比如用个链表存储系数,很容易就能写出这样的程序。

一共要展开n项,但由于越往后多项式的长度越长,所以时间复杂度为O(n^2)。

4、O(n)

在n^2时间复杂度的基础上我们尝试继续分析以找出更快的算法。在上一步多项式展开过程中,其实我们不仅求出了和是A的组合数,还求出了和是其它所有自然数的组合数,在多项式全展开的过程中实际上我们做了很多不必要的工作。

因此,可否存在某个方法,直接就得到次数为A项的系数呢?

答案是肯定的。求函数f(x)在x=0点的泰勒级数展开式的第A项的系数即可,具体来说就是求函数f(x)在0点的A阶导数。使用数值方法计算A阶导数只需要取0点附近的A个数,然后通过简单的递归就能得出,在这里不在赘述。因此,我们找到了一种O(n)时间复杂度的方法。

5、O(1)

这。。。真的存在吗?反正我是没找到。

你可能感兴趣的:(数学的力量(四))