• 程序员面试金典 chapter1 arrays and strings

    第一题 翻转字符串

    把一个给定的字符串反转 笨方法,遍历整个给定的string,将数组string[n]中的第i个元素与第[n-1-i]个元素对调,下面为代码示例:

    class Reverse {
    public:
        string reverseString(string iniString) {
            // write code here
            char c;
            int len = iniString.length();
            for(int i=0; i < len / 2; i ++)
            {
             c = iniString[i];
                iniString[i] = iniString[len - i - 1];
                iniString[len - i - 1] = c;
            }
            return iniString;
        }
    };

    第二题 判定字符串中字符是否相同或不同

    … 不细说、代码示例在下面:

    class Different {
    public:
        bool checkDifferent(string iniString) {
            // write code here
            for(int i=0;iniString[i]!='\0';i++)
                {
                for(int j=i+1;iniString[j]!='\0';j++){
                    if(iniString[i] == iniString[j])
                        return 0;
                }
            }
                return 1;
        }
    };

    第三题 确定两串乱序同构

    (我觉得和第八题是一样的,这里是第八题的描述: 请将这个算法编写成一个函数,给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成。唯一不一样的地方可能就是第八题要求用并且只用一次issubstring这个函数吧。这里省略第八题。 )

    给出的代码结构为:

    class Same {
    public:
        bool checkSam(string stringA, string stringB) {
            // write code here
    };

    我的第一个想法很简单,遍历整个stringA和stringB,当在B中能找到该元素就在B数组中删除这个元素,直到最后判断B是否为空。但是….总之我这么想着写有误,会漏判应该返回 “false”的情况,下面为错误的代码示例:

    class Same {
    public:
        bool checkSam(string stringA, string stringB) {
            // write code here
            if(stringA.length()!=stringB.length())
                return false;
           for(int i=0;stringA[i]!='\0';i++){
               for (int j=0;stringB[j]!='\0';j++){
                   if(stringA[i] == stringB[j]){
                       stringB.erase(j,1);
                   }
               }
           }
            stringB.erase('\0');  //delete the last element in the string
            if(stringB.empty())
                return true;
            return false;
        }
    };

    既然漏判了一个原本应该为”false”的情况那么我就加判一个,同样遍历A,当不能在B中找到A的该元素时我就立即返回”false”.一下为通过的代码示例:

    class Same {
    public:
        bool checkSam(string stringA, string stringB) {
            // write code here
            if(stringA.length()!=stringB.length())
                return false;
           for(int i=0;stringA[i]!='\0';i++){
               for (int j=0;stringB[j]!='\0';j++){
                   if(stringA[i] == stringB[j]){
                       stringB.erase(j,1);
                       break;
                   }
                   else if((stringA[i] != stringB[j]) && (j == stringB.length()-1))
                       return false;
               }
           }
            stringB.erase('\0');
            if(stringB.empty())
                return true;
            return false;
        }
    };

    在看别人的讨论中看到大神们是这么想的,还是一样先从最简单的长度开始比较,然后定义一个存放了256个”0”的新数组,当在遍历的时候将A中的元素和B中的元素逐一进行记录,遇到A中的第n个元素该新定义的的数组的第[A[n]]个”0”自增1,而同样,遇到B的元素时自减1.也就是说若A和B是完全相同的组合数组那么意味着这个新定义的数组始终应该保持“0”的平衡。下面是该方法的代码示例:

    class Same {
    public:
        bool checkSam(string stringA, string stringB) {
            // write code here
            char count[256]={0};
            if(stringA.size()!=stringB.size()) return false;
              
            for(int i=0;i<stringA.size();i++)
            {
                count[stringA[i]]++;
                    count[stringB[i]]--;
            }
            for(int i=0;i<256;i++)
                if(count[i]!=0)
                    return false;
            return true;
        }
    };

    我自己的本方法虽然最后运行结果正确但是运行时间相当长,我的正确代码运行时间为70ms而大神的代码只需要1ms。

    第四题 将字符串中的空格全部替换为”%20”

    给出的代码格式为:

    class Replacement {
    public:
        string replaceSpace(string iniString, int length) {
            // write code here
            
        }
    };

    简单的想,首要任务应该就是找找这个字符串里面哪里有空格,哪里有空格就在哪里添加那个”%20”呗。简单的代码示例为:

    class Replacement {
    public:
        string replaceSpace(string iniString, int length) {
            // write code here
            string str;
            for(int i=0;i<length;i++)
            {
                if(iniString[i]==' ')
                {
                    str+="%20";
                }else
                {
                    str+=iniString[i];
                }
            }
            return str;
        }
    };

    第五题 压缩字符串

    利用字符重复出现的次数,编写一个方法,实现基本的字符串压缩功能。比如,字符串“aabcccccaaa”经压缩会变成“a2b1c5a3”。若压缩后的字符串没有变短,则返回原先的字符串。

    好吧,一开始没怎么明白看了好几遍输出才知道卧槽根本不存在压缩后面不带数字的情况啊。。。。思路很简单总之就是j的循环在i里面,期间犯了个很大错误导致最后一个元素会打印不出来,原因在于内循环的j也设了不能到字符串最后的条件,来看一下这个判断:

    for(int i=0;i<iniString.length();){
                for(j=i;j<iniString.length();){
                    if(iniString[i] == iniString[j]){
                        count++;
                        j++;
                    }
                    else{
                           str+=iniString[i];
                           str+=to_string(count);
                        count=0;
                        break;
                    }
                }
                i=j;
            }

    我估计之所以不能get到最后的元素可能是因为这样写的后果。。。j到不了字符串最后的’\0’,以至于最后比较的时候没办法”j++”。所以最终通过代码为:

    class Zipper {
    public:
        string zipString(string iniString) {
            // write code here
            string str;
            int j=0;
            int count=0;
            for(int i=0;i<iniString.length();){
                for(j=i;;){
                    if(iniString[i] == iniString[j]){
                        count++;
                        j++;
                    }
                    else{
                           str+=iniString[i];
                           str+=to_string(count);
                        count=0;
                        break;
                    }
                }
                i=j;
            }
            
            if(str.length() >= iniString.length())
                return iniString;
            return str;
        }
    };

    第六题 像素翻转

    需要返回一个旋转后的NxN矩阵 函数样例给出如下:

    class Transform {
    public:
        vector<vector<int> > transformImage(vector<vector<int> > mat, int n) {
            // write code here
        }
    };

    既然不能定义一个新的temp数组可能从替换的角度来思考这个问题更简便一些,首先从矩阵最外围的一圈来看:

    for(int i=0;i<n/2;i++){
     //... ...
    }

    假如说该原始矩阵有单数层那么理应只需要进行(n-1)/2次分层就可以了,比如三层,去掉最外围就只剩下中间的一个元素,应该不动。若是偶数层正好除尽,进行n/2次的处理。那么对于每一层来说有四条边,就在每一层中间做需要做四次的操作:

    for(int i=0;i<n/2;i++){
        for(int j=i;j<n-1-i;j++){
            mat[i][j]=mat[n-j-1][i];
      }
    }

    第一次处理第一行的元素,变换后的矩阵第一行由第一列来取代,将内循环的j看作是列的话,那么挨个的元素替换就相当于是将该列最后一个元素[n-0-1][0]替换到了[0][0]的位置,而后以此类推。 第二次处理应该处理刚刚替换的位置的元素也就是第一列的元素,第一列的元素是被最后一行的元素锁替代,那么代码示例为:

    mat[n-j-1][i]=mat[n-i-1][n-j-1];

    也就是说第一列最后一个元素[n-0-1][0]被替换成了[n-0-1][n-0-1]也就是最后一行的最后一个元素了,以此类推。 继续第三次是把刚刚替换了第一列的元素,也就是原矩阵最后一行的元素进行处理,换成原矩阵的最后一列元素。最后将原矩阵第一行的元素放入原矩阵最后一列的元素,第一层就替换完毕了。 最后完整代码示例为:

    class Transform {
    public:
        vector<vector<int> > transformImage(vector<vector<int> > mat, int n) {
        // write code here
        int temp;
        for(int i=0;i<n/2;i++){
          for(int j=i;j<n-1-i;j++){
              temp = mat[i][j];
              mat[i][j]=mat[n-j-1][i];
              mat[n-j-1][i]=mat[n-i-1][n-j-1];
              mat[n-i-1][n-j-1]=mat[j][n-i-1];
              mat[j][n-i-1]=temp;
          }
      }
        return mat;
        }
    };

    第七题 清除矩阵中整行整列

    还是遍历整个矩阵,也就是一个二维数组,找到0就返回flag该行该列都应该为0。那么返回的这个flag通过定义两个新的一维数组来实现简单的记录,通过代码示例为:

    class Clearer {
    public:
        vector<vector<int> > clearZero(vector<vector<int> > mat, int n) {
            // write code here
            //vector<int> row(n,1),column(n,1);
            int row[n],column[n];
            for(int i=0;i<n;i++){
                row[i]=0;
                column[i]=0;
            }
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(mat[i][j] == 0){
                        row[i]=1;
                        column[j]=1;
                    }
                }
            }
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(row[i]==1 || column[j]==1){
                        mat[i][j]=0;
                    }
                }
            }
            return mat;
        }
    };
  • 深夜惊醒程序员

    多年未曾联系的发小突然致电询问学习编程、从哪开始,我也有些迷茫 一时间不知道如何措辞 话又说回来 我也不是一个正经能称得上程序员的毕业生,我离那个程序员的称呼差得可不是一星半点啊。

    再说这位朋友 985工程下的名校自动化专业在读生,说着我都心里犯尴尬的专业 如今这个社会也可以越来越不关心所谓 专科出身 这样的帽子了。且说所谓计算机专业,那些成为网民手下的码农、程序员的人 相当一部分出自自动化 通信 电子 机械,甚至数学 物理这些兄弟姐妹类似的旁系。这些统称为工科的专业大都殊途同归变成了不同的码农 操纵着不同的编程语言、这是我上大学的时候一位出身通信的学长告诉我的 现在看来的确是不可争的事实。彼时我还在读 余果的 全栈工程师自我修养,想来现在的社会分工于二、三十年前相比精致许多,所谓软件工程师 嵌入式工程师 web工程师 硬件工程师 前端工程师 后端工程师,呵、当然还有全栈工程师。看看那一个个的头衔 哪一个不是人们嘴里、文字里的码农,眼里穿着冲锋衣牛仔裤的程序员。同样是理论物理出身的我的父亲,在三十年前大学毕业的时候手里只有一本翻译的FORTRAN教材,三十年后的今天,几乎你想学的语言,你想学习的方向,都只需要简单的通过键盘敲在搜索框里,丰富的资源都在回车之后一览无遗。我想所谓码农的分工之细正好对上了开头我的一时语塞,现在说想学编程,不能不说这是一个极其复杂而艰难的问题,我根本无从说起。作为一个半路出家了一年的应届毕业生来说,我接触的编码实在少之又少,每天醒来都觉得世界又变了,有太多新的语言,新的框架和许许多多我叫不上来的技术正在世界每个角落萌发生长。往往清晨起床,在V2EX上浪一浪,就满眼飘着的都是诸如Vue.js,ES6,PHP7这些跟我的生活无关却又息息相关的技术名词,坐在高脚凳上,两腿就开始发虚了,一声长叹,这个世界啊,这个社会啊,我是否会在一波又一波的浪潮中死无葬身之地。在这个无论是工资还是智商都追不上的社会里如何避免食不果腹、衣冠不整、开始成为每天头顶着的无形压力,谁说不恐惧呢,我打包票,城市里,那些夜晚亮着灯的办公室中,每个所谓的程序员或多或少都有这样的技术栈恐惧感。

    所谓30的程序员、一语成谶。

    我们这些初入社会的捣乱分子,还能年轻多久,还能趁着这股激情疯狂多久。在那些程序员的世界里,有一个长着章鱼脚的猫看管的圣地,时不时那里的风景会带来些许兴奋,些许失落,兴奋是别人的院子永远绿满格,而失落则是不管发了几回毒誓,自己的院子还是空空荡荡,甚至当开始寻摸下一份工作的时候都怕拿不出像样的项目。其实从哪里开始的都不重要,长久的坚持才能时不时的消除那份莫名的恐慌吧。

    在这个不大不小的尴尬年龄,从前过往,不知曾经爱过的人如今在哪里,愿在漫长的未来里,除了爱情,彼时,我们还能拥有此时的激情。

    这些都是你给我的爱

    我不想成为一名人们说的程序员、工程师,在我慢慢走近编程的这条路上,有过太多的的骄傲自满也有过数不清的煎熬和自卑。对于朋友,我只想说,找一个感兴趣的方向不难,甚至在未来的几年里成为一个性感又受众的所谓大数据工程师也并不难,我给不了太多的建议,那么、说说你编程想做什么吧

  • Express开发陷入异步圈和回调坑

    接着上个礼拜的jekyll结束后这个星期公司依然地广人稀 我第一次开始认认真真的看express4.x这个框架 慌是肯定的 明明手里已经预订了好几个MEAN stack的博客准备去看 其实连最基本的jQuery和AJAX都不会用 如何能谈Angularjs呢 除了最简单的routing和基本的mongoose CRUD之外 为了完成基本功能的express也写过了 想要真正的静下心来看Doc反而越看越慌 今天一天就深深的陷入了回调函数的坑里

    不讨论回调和异步、同步的关系和不同了 请自行google … … 因为我也没整明白 简单讲一下我试了一天对这几个的理解

    先说同步 我理解的同步就是逻辑自上而下 默默突然回想起做VerilogHDL的时候学过这么两个词blocking和non-blocking 那么这个阻塞和非阻塞又和同步异步有什么关系和区别呢

    其实按照理论是没有什么关系的 同步嘛相当于调用者主动 一旦该调用返回了有值了 异步就反一反 相当于被调用者的状态反馈给调用者

    这个打个比方 我们国内很多客服态度可能时好时坏 但是这个服务速度是有的 你好比打个电话问问客服我有个什么问题不能解决 这个客服呢就在电话那头给你解决 在问题解决之前或者说在这个事情有结果之前你一直都是在跟客服进行沟通的

    那么英国这里呢 实在等不起 你打个电话 他说”Alright mate, but I can do nothing to help you right now I’ll give you a call back later, OK?” 这就是异步了 他解不解决问题在他 在你等他给你打回来通知结果之前 你是正常过日子的 没有24小时一直在通电话

    所以说呢同步还是异步只是说明了消息机制 communication嘛 对伐 而阻塞非阻塞可能就是描述了当在等待的状态 就是说非阻塞是会正常过日子的等结果的 中间呢因为这个英国服务太糟糕了 只能是不是check一下状态如何了 这个阻塞啊就意味着问题太大了 没法正常过日子等着客服解决了 不管什么时候返回结果 这期间都只能“挂起” 就好比只能呆滞的躺在床上等一场我想我要挂了的考试最终成绩一样

    再说这个回调,这个吧我就记住这么两条,一般情况下同步回调 这个回调函数最后执行 如果是异步回调 那人家不一定就最后执行 如果要等该函数执行完以后在执行另一条 那么这个执行语句必须放在回调函数内

    想想真的是慌得呀 一本正经好像说的跟真的一样 我就先给自己备忘一下 简单的注册功能 本来想把MVC弄得好看一些 不要把所有函数啊判断啊都放在一起混了 结果就被异步啊回调啊尴尬了

    var IsExisted = function(data,callback){
      userdb.findOne({'useremail':data},function(err,doc){
    
        console.log(data);
    
        if(!err){
          //console.log(doc);
          if(!doc){
            console.log('new user');
            //console.log(doc);
            return_value = 1;
            callback(return_value);
          }
          else
          {
            console.log('user existed');
            return_value = -1;
            callback(return_value);
          }
        }
        else{
          console.log(err);
        }
      });
    }