以空间换时间思想

来源:互联网 发布:二维码点餐软件开发 编辑:程序博客网 时间:2024/04/29 23:13

    今天面试时,最后一个问题问到了空间换时间的东东,说实在,真没怎么鼓捣过这个,网上找了点资料,贴来看看,末尾附有原帖地址,需要的可以爬链接……

    以前看过一篇文章“优化C代码常用的几招”,作者提到的第一招就是“以空间换时间”,还举了一个例子,由于比较经典,引用一下:计算机程序中最大的矛盾是空间和时间的矛盾,那么,从这个角度出发逆向思维来考虑程序的效率问题,我们就有了解决问题的第1--以空间换时间。比如说字符串的赋值:

   

    使用的时候可以直接用指针来操作。

    从上面的例子可以看出,AB的效率是不能比的。在同样的存储空间下,B直接使用指针就可以操作了,而A需要调用两个字符函数才能完成。B的缺点在于灵活性没有A好。在需要频繁更改一个字符串内容的时候,A具有更好的灵活性;如果采用方法B,则需要预存许多字符串,虽然占用了大量的内存,但是获得了程序执行的高效率。笔者在编程练习过程中也遇到了不少可以用空间换时间的算法,把它们收集起来,以便初学者学习查阅。

 

 

    桶式排序算法

    数组的排序算法很多,其中快速排序是在实践中最快的已知排序算法,它的平均运行时间是O(nlogn),堆排序算法在最坏的情况下,其时间复杂度也能达到O(nlogn)。相对于快速排序来说,这是它最大的优点,但是它需要一个记录大小供交换用的辅助存储空间——其实这也是用空间换时间的表现。

    但是,当数组的元素是一些较小的整型数据(小于1000000)时,用“桶式排序算法”可以使时间复杂度降到O(N),可以很快地对年龄,成绩等整型数据进行排序。此外还可以使用桶式排序的方法求素数表。

    “桶式排序算法”的代码也很简单,只要建立一个长度为max的字符数组就可以了,代码如下:

 

   

 

    求第n个子集的所有元素

 

    一个好汉三个帮,三个好汉九个帮,九个好汉二十七个帮,...停,今天不是让你算n个好汉几个帮(有兴趣的网友可以自己算),我们来看这个集合{ 1, 3, 9, 27, 81, ... },这个集合是一个递增的无限集,每个元素都是3的幂。

    我们把这个集合的所有子集按照元素和从小到大的顺序排好: {}(空集), { 1 }, { 3 }, { 1, 3 }, { 9 }, { 1, 9 }, { 3, 9 }, { 1, 3, 9 }, ...

    现在给定一个正整数n,求第n个子集的所有元素,并按从大到小的顺序排列好

    例:

    n的值    结果
    1        { }
    4        { 3, 1 }
    6        { 9, 1 }
    500      { 6561, 2187, 729, 243, 81, 3, 1 }    
    细节要求:
    1. n的范围: n >= 1 ,unsigned int
    2. 接口:    void HeroNeedThree(INT64* subset, unsigned int n);
    其中INT64是指64位整数,可以用 typedef long long INT64; 也可以自定义
    subset就是存放结果的数组,其中subset[0]存放结果子集的元素个数,
    然后子集元素从大到小存入subset[1],subset[2],......

 

    算法分析:除去空集,观察前n个子集

    {1},----------------------------------------2^0 个子集

    {3},{1,3},--------------------------------2^1 个子集

    {9},{1,9},{3,9},{1,3,9} --------------2^2 个子集

    {27},{1,27},{3,27},{1,3,27},{9,27},{1,9,27},{3,9,27},{1,3,9,27}----------------------------------------2^3 个子集

    从上表可以看出对于有k个元素的集合,对应的有2^k(k<=32)个子集,而且每一行子集序列的第一个子集元素的大小恰好是3^0,3^1,3^2,3^3,…3^(k-1)。

    我们把n转换成二进制数,当n=5时,它的二进制数为0000…0101(共32位),即2^0+2^2,对应的子集为{3^03^2},即{1,9};

    当n=13时,它的二进制数为0000…1101(共32位),即2^0+2^2+2^3,对应的子集为{3^03^23^3},即{1,9,27};

    由此可得,要求第n个子集(注意还要加上空集,实际上是第n+1个),则只需将其转换成32位的二进制,则它就是所求的子集的二进制序列。把二进制中值为1的位对应的元素作为3的指数,求出3的幂就是对应的元素。

    根据此算法我们很容易的编出程序:

 

   

   在上面的程序中,我们每次都要去求3的m次幂,虽然我们采用分治法求幂,速度较快,但是当n值教大时,还是需要很多时间的,因为long long类型是32位的,我们可以预先把3的0-31次幂全部求出来,存放在数组中,这样就不用每次都进行求幂运算了,可以节省不少时间。同样的,我们也可以把2的0-31次幂全部求出来,存放在数组中,这样就不必每次都去判断二进制数中各个1所在的位置,而直接用下标表示了。

改进后的代码如下:

   

以空间换时间算法集锦:http://blog.pfan.cn/goal00001111/25028.html

此外,下面两帖子的探讨也有可观之处:

http://bbs.pfan.cn/post-295761.html

http://bbs.pfan.cn/post-293442-1.html

 

原创粉丝点击