算法练习心得

算法这东西,一直是令很多人头疼的东西(当然我也是),但是想做出高效的程序,还真离不开。其实很多算法已经集成进了各种编程语言的库,系统调用库,似乎足够用了。比如Java中的TreeSet使用红黑树存储元素,c++中的map用到了红黑树,linux内核在调度进程的时候也用到了红黑树。由此可见,高效的算法会很快推广,从系统到应用都可以派上用场。

回想一下,工作中用得多吗,这个看情况,对于安卓客户端程序,用户有一个延迟体验的晃动值100-200ms(书上说的,哈哈),当然这不适用于游戏场景,如果超过100ms,体验就比较糟糕,按钮点击响应时间或许可以慷慨一点。据我以往的经验看,就安卓客户端,有几个场景会遇到问题,首先是屏幕的显示刷新,还有就是音频相关的应用,还有文件的加载编辑。显示这一块儿是做过最多的,按理说目前客户端最重要的还是显示(但是安卓系统中声音线程的优先级高于UI线程,可能手机通话的重要性更高),也是最吸引人的地方,比如酷炫的动画,然而仅靠安卓自带的动画接口,似乎有些限制,每次玩狂野飙车(gameloft出品)的时候,就被动画特效吸引,这种科技感十足的动画是怎么搞的,就像变形金刚,而且给按键加上了音效,这个确实很棒,目前很多日常使用的app还没有这样做,未来可能会比较普遍。毫无疑问,想做出不一样的特效,还真得研究算法,毕竟你没有接口方法可调用。而且算法这东西,一般比较耗时,而且效果往往还不够理想。算法确实需要长期的积累,狂野飙车的游戏已经有15年之久了,好的东西,确实不是一蹴而就。这又让我想起了以前的工作经历,由于工作需要,我得在本地实现一个绘图库,因为安卓上层提供的方法不够高效。于是就自己上网查资料,去实现画线,抗锯齿的特效,因为开始是用C开发的,用筚路蓝缕一点不为过,C嘛,连vector都没有,还得用malloc,free,realloc这些去定义各种结构体,各种函数,宏,位运算,结果搞了几个月,效果也不理想。无奈只好向库低头,skia真香,哈哈。可是在研究skia的时候,我发现有些代码文件是源自2003年的,不得不说,好东西真是可以传承的。这不禁又让我想起最近的一件事,为了打发时间,研究一下linux内核吧,毕竟是最大的开源项目,全球1000多位精英程序员历经近三十年的杰作。Linus Benedict Torvalds确实是教父级的人物,一个linux,一个git,记得刚毕业那会儿,git命令真是让人头疼,可是再到后来,每次敲击git,都有一种莫名的快感,难道这就是开源精神的召唤吗。学习内核,绝不是好高骛远,而是觉得一知半解,危害匪浅。最近安卓11发布了,安卓的内核也更新到了5.8.8。上层的变动如何,不太清楚,应该会比较大吧,内核中很多东西变化不是很大,比如进程相关的结构体task_struct(很复杂有700多行)中,进程优先级的一些变量,依然好好的躺在那里,和10年前一模一样。这些不变的东西,我觉得学习的价值更大。不得不佩服搞内核的这些人,在进程调度的时候,嫌弃红黑树时间复杂度logN,不够高效,可以做到log(1),简直太疯狂了。

扯得有点远了,今天就练习了一道比较简单的算法体,也是费了半天劲,可算编译过了,捡起了我心爱的c++。有时我觉得,算法题的意义主要是锻炼思维。话不多说,上代码。

题目描述如下:

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

实现代码如下:

class Solution {

public:

    char getMaskChar(int num, int mask){

        char numChar;

        if(num <= 6){

            if(mask ==  3){

                return ' ';

            }

            numChar = mask + 97 + (num - 2)*3;

        }else if(num == 7){

            numChar = mask + 112;

        }else if(num == 8){

            if(mask == 3)

                return ' ';

            numChar = mask + 116; 

        }else{

            numChar = mask + 119;

        }

        return numChar;

    }

 

    vector<string> letterCombinations(string digits) {

        vector<string> result;

        int size = digits.size();

        if(size == 0) return result;

        for(int mask = 0; mask < (1 << size * 2); mask++){

            string tempStr;

            for(int i = 0; i < size; i++){

                int move = (size - i - 1)*2;

                char tempChar = getMaskChar(digits[i] - 48, (mask & (3 << move)) >> move);

                if(tempChar == ' ')

                    break;

                tempStr.push_back(tempChar);

            }

            if(tempStr.size() == size)

            result.push_back(tempStr);

        }

        return result;

    }

};

可能写得不够简洁,但我觉得简洁的东西不一定高效,c++只要稍微使用一下位运算,效果就会出乎意料的好。这个题用从数学角度看不难,可是编码实现,还是有些棘手,解决的关键是如何表示所有的可能情况,每个数字可以用两位二进制数表示,有些数字可以是四个字母,大部分是三个,需要加一些判断。

其实,想要程序高效运行,除了选用合适的算法,如果掌握一些常用的技巧,也可以提升几十倍,比如减少函数调用,减少对象创建与引用,循环展开(利用多核处理器一次处理多条指令的特性),甚至结构体中也能压榨出字节。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值