zoukankan      html  css  js  c++  java
  • 算法面试题解答(二)

    在面试中,我们经常被问到Coding的问题,要求用伪码或者某种语言解决一个问题,由于平时我们都依赖IDE来debug找错,所以很容易写出有错误的程序,而且没有调试,导致有些错误极难被发现,下面列举一些常见错误,并以三个题目的实践作为例子告诉自己:错误很容易发生!!!请注意验证自己的程序。

    1. 边界条件:
      1. 循环变量的起始点、结束点和增减是否正确;
      2. 递归调用的结束条件; 
      3. 对于输入,是否考虑可能很大或者很小的情况,比如,对某个序列进行rotate,这个次数如果是特别大,至少打过序列长度,这种情况考虑了吗;
      4. 空间边界,内存、字符串、数组的大小对吗,是否存在差1和越界情况
      5. 数据结构边界,链表的头和尾正确处理了吗,指针指向的对吗?
    2. 输入假设:
      1. 如果输入的是指针,你是否考虑指针为NULL的情况;
      2. 如果输入字符串或者数组长度为0,会如何?
      3. 如果输入是数组或者字符串,你是如何知道其长度的;
      4. 如果输入的是字符串,并对字符串进行某种处理,你是否处理了可能的特殊字符,比如空格等;是否考虑了大小写问题?
      5. 如果设计到字符串到数字的转换,你是否考虑了负数、是否考虑了浮点数;
    3. 内存分配和释放
      1. 计算需要的内存大小时,是否考虑了若是字符串,需要多分配一个字符大小;是否考虑了重叠内存?
      2. 分配的大小是否合适;
      3. 分配的内存由谁释放,是否已经释放;
    4. 指针
      1. 指针的移动是否正确,到底应该移动多大?

    引用的文章中列举很多Code Review时会被发现的问题,可以作为一个参考。

    问题1: 对一个数组,只能swap相邻的两个元素,给定一个数组,和可以交换的次数,求最小的数组。比如{7,6,5,4,3,2,1},如果只交换一次,那其最小值是{6,7,5,4,3,2,1},也就是假定索引小的权重更大。

    #include <iostream>
    #include <assert.h>
    
    using namespace std;
    
    void GetSmallestSwap(int *src, int len, int start,int swaplimit) // start and end are index, [0, len-1]
    {
        if(swaplimit ==0 || start>=(len-1)) //递归的结束条件,一般递归参数都可能成为结束条件的一部分,否则,那个参数可能就不需要作为递归参数,否则无法处理1,2,3,4的情况
            return;
        assert(swaplimit>0);
        int j = start + swaplimit;
        if(j>=len) j = len-1;
        int min = src[start];
        int IndexofMin = start;
        for(int k = start;k<=j;k++) //今天犯得错误都在这一行,k要从start开始,而不是0开始;k要到==j结束,而不是<j结束,因为j是包含在内的
        {
            if(src[k]<min)
            {
                min = src[k];
                IndexofMin = k;
            }
        } // find the first smallest num in the array
        int swaps = 0;
        for(int k = IndexofMin;k>start;k--)
        {
            swap(src[k],src[k-1]);
            swaps++;
        }
        GetSmallestSwap(src, len, start+1, swaplimit - swaps);
    }
    
    int main(int argc, char **argv)
    {
        int a[] ={7,6,5,4,3,2,1};
        GetSmallestSwap(a, 7,0,11);
    }

    注释:

    1. for/while等循环的开始和结束条件;
    2. 递归的结束条件,递归参数都需要考虑作为结束条件

    问题2: Two sorted array. Find kth smallest element: O(logK):

    #include <iostream>
    #include <assert.h>

    using namespace std;

    int FindKthElement(int *src1,int len1, int start1, int end1, // both index are inclusive [start, end]
                       int *src2,int len2, int start2, int end2,
                       int k) // if found, return 0, else, return 1;
    {
        int len1_0 = end1 - start1 + 1;
        int len2_0 = end2 - start2 + 1;
        if(k==0) return 1;
        if((len1_0+len2_0)<k)
            return 1;
        assert((end2>=start2)||(end1>=start1));
        if(k==1) //错误,之前没有检查k为1的情况,因为k=1时,我们在下面代码中并没有处理,或者对j的处理可以确保其可以处理k为1的情况,比如j = k/2>1?k/2:1;但这时还得处理k=0的特殊情况
        {
            if(src2[start2]>src1[start1])
                cout<<src1[start1]<<endl;
            else
                cout<<src2[start2]<<endl;
            return 0;
        }
        if(end1<start1 && end2>=start2)
        {
            cout<<src2[start2]<<endl;
            //src2[start2] is the K
        }
        else if (end2<start2 && end1>=start1)
        {
            cout<<src1[start1]<<endl;
            //src1[start1] is the K
        }

        int j = k/2;
        /*if(j<1)   //如果使用这种方式处理k=1的情况,而k=1,j也=1,是不符合j=k/2这个规律的,这样后面的处理会改变逻辑,并不是很好的特殊情况处理方法
            j = 1;
    */
        int reduced1,reduced2;
        int l, m;
        if(len1_0>=j && len2_0>=j)
        {
            l = start1+j;
            m = start2+j;
            reduced1=reduced2 = j;
        }
        else if(len1_0>=j && len2_0<j)
        {
            l = start1+j;
            m = end2+1;
            reduced1 = j;
            reduced2 = len1_0;
        }
        else if(len2_0>=j && len1_0<j)
        {
            l = end1+1;
            m = start2+j;
            reduced1=len1_0;
            reduced2 = j;
        }
        if(src1[l-1]>src2[m-1])
            return FindKthElement(src1,len1,start1,end1,src2,len2,m,end2, k-reduced2);//end1处出了错误,开始写成了l,我们每次尽量减少看k/2个数据,但有时减少的要比k/2的少
        else if(src1[l-1]<src2[m-1])
            return FindKthElement(src1,len1,l,end1,src2,len2,start2,end2, k-reduced1);
        else
        {
            //output it
            cout<<src1[k-1]<<endl;
            return 0; // the src1[k-1] or src2[m-1] is the kth element;
        }

    }

    int FindKthElementInArray(int *src1, int len1, int *src2,int len2, int k)
    {
        return FindKthElement(src1,len1,0,len1-1,src2,len2,0,len2-1,k);
    }
    int main(int argc, char **argv)
    {
        int a1[]={5,6};
        int a2[]={1,2,3,4,7,8};
        FindKthElementInArray(a1,2,a2,6,6);
    }

    注释:

    1. 递归调用的结束条件不完整。 在这个题目中,我们需要递归参数有更多的分析,否则很容易出错。
    2. 递归调用应该使用哪个值作为参数, 哪个该+1,-1,哪个该不动,都要搞清楚了;

    问题2: 将一个数学表达式构造为二叉树,数字和运算符是树中的节点

    binarytreenode * buildBSTfromSubStringInBracket(char *src,int len, int begin, int *endpos)
    {
        if(src[begin] != '(') return NULL;
        stack<binarytreenode *> strstack;
        for(int i = begin+1;i<len;)
        {
            int endpos = 0;
            int digitTemp = 0;
            binarytreenode *subtree = NULL;
            if(src[i] == '(')
            {
                subtree = buildBSTfromSubStringInBracket(src, len, i, endpos)
                i = endpos;
                if(strstack.size()>0 && strstack.top() is * or / operator)
                {
                    binarytreenode *t1 = strstack.pop();
                    binarytreenode *t2 = strstack.pop();
                    t1->left = t2;
                    t1->right = subtree;
                    strstack.push(t1);
                }
                else
                {
                    strstack.push(subtree);
                }
            }
            else if (src[i] == ')')
            {
                binarytreenode *t1 = strstack.pop();
                while(strstack.size()>0)
                {
                    if(t1 is not operator)
                    {
                        binarytreenode *t2 = strstack.pop();
                        assert(t2 is a operator);
                        binarytreenode *t3 = strstack.pop();
                        assert(t2 is not a operator);
                        t2->left = t3;
                        t2->right = t1;
                        t1 = t2;
                    }
                }
                *endpos = ++i;
                return t1;
            }
            else
            {
                if(src[i] is a digit)
                {
                    while(src[i] is a digit)
                    {
                        int dt = src[i] to didit;
                        digitTemp = 10*digitTemp +dt;
                        i++;
                    }
                    binarytreenode *t = new binarytreenode(digitTemp);
                    if(strstack.size()>0 && strstack.top() is * or / operator)
                    {
                        binarytreenode *t1 = strstack.top();
                        strstack.pop();
                        binarytreenode *t2 = strstack.top();
                        strstack.pop();
                        t1->left = t2;
                        t1->right = t;
                        strstack.push(t1);
                    }
                    else // is - or +;
                    {
                        strstack.push(t);'
                        digitTemp = 0;
                    }
                }
                else if(src[i] is a operator)
                {
                    binarytreenode *t = new binarytreenode(src[i]);
                    strstack.push(t);
                    i++;
                }else if(src[i] is space)
                {
                    i++;
                }
            }
        }
        binarytreenode *t1 = strstack.pop();
        while(strstack.size()>0)
        {
            binarytreenode *t2 = strstack.pop();
            binarytreenode *t3 = strstack.pop();
            t2->left = t3;
            t2->right = t1;
            t1 = t2;
        }
        return t1;
    }

    注释:

    1. 没有考虑数字是负数以及是浮点数的情况;
    2. 还有一些被检查出来的错误:有个地方忘了i++,有个++i的地方错用微i++;

    引用:

    http://blog.csdn.net/softstars/article/details/2249234

  • 相关阅读:
    超轻量级三级展开列表
    5 Reasons Your Javascript Stinks
    xhEditor 轻量级文本编辑器简单配置
    简单SEO攻略
    ashx文件
    xml中xPath的使用
    关于MSDN,文章索引
    关于Jquery中 “$(document).ready(function(){ })”函数的使用
    在Jquery使用过程中用到了css属性:opacity(不透明度),cursor (光标的类型、形状)
    初识Silverlight
  • 原文地址:https://www.cnblogs.com/whyandinside/p/2775732.html
Copyright © 2011-2022 走看看