• [微软面试100题]5160


    第五十一题:输出所有和为n的连续正数序列
    方法1:从1遍历到n/2,算出所有sum,如果sum刚好等于n则输出,效率极低。
    方法2:用一个变量b标志连续序列的开头,e表示结尾。如果序列的sum<n,则e++;如果sum>n,则b++。复杂度O(n)
    void constSumSequence(int n){
        int b=1,e=1,sum=1,bound=n/2+1;
        while(e<=bound){
            if(sum==n){
                for(int k=b;k<=e;++k)cout<<k<<" ";
                cout<<endl;
                sum+=(e+1-b);
                b++;
                e++;
            }else if(sum>n){
                sum-=b;
                b++;
            }else{
                e++;
                sum+=e;
            }
        }
    }

    第五十三题:输入字符串,打印字符串所含字符的所有组合

    以第一个字符为分组。每组还没到最后两个字符时,往下递归。到最后两个时,先打印一次,调换了再打印一次。
    把所有字符一次放到字符串第一位,依次进行上面算法
    如a组abc  acb, b组bac bca  c组cba  cab
    //将第i个字符与后面的字符串对掉
    void swapchar(char *c,int i,int n){
        char tmp=c[i];
        for(int k=i+1;k<n;++k){
            c[k-1]=c[k];
        }
        c[n-1]=tmp;
    }
     
    void helper(char *c,int i,int n){
        if(i<n-2){//还没到最后两个字符时,swap
     
            char tmp[n+1];
            for(int k=0;k<n;++k)tmp[k]=c[k];
            tmp[n]='\0';
     
            helper(c,i+1,n);
            swapchar(tmp,i,n);
            helper(tmp,i+1,n);
        }//到最后两个,打印一个,对调后再打印一次
        cout<<c<<endl;
        swapchar(c,i,n);
        cout<<c<<endl;
    }
     
    //把每一个字符依次放到第一
    void final(char *c,int n){
        for(int i=0;i<n;++i){
            char tmp[n+1];
            for(int k=0;k<n;++k)tmp[k]=c[k];
            tmp[n]='\0';
            char firstChar=c[i];
            tmp[i]=c[0];
            tmp[0]=firstChar;
            helper(tmp,1,n);
        }
    }

    第五十四题:调整数组位置使奇数放在数组前部,偶数后部。复杂度为O(n)

    记录一个index,然后从前往后扫描数组,扫到一个奇数就把奇数和index上的数对调,然后index++。
    不知道为什么网上这一题其他人的答案都好复杂什么从两边同时扫。。。明显简单问题复杂化了吧?
    void helper(int *num,int n){
        int i=0;
        for(int j=0;j<n;++j){
            if(num[j]%2!=0){
                int tmp=num[i];
                num[i]=num[j];
                num[j]=tmp;
                i++;
            }
        }
    }

    第五十六题:最长公共子串

    定义f(m, n)为Xm和Yn之间最长的子序列的长度
    若f(m-1,n-1)已知,那么这时候检查Xm和Yn
    1.如果 xm == xn,那么有,说明最后一位应该加入公共子序列,所以其长度 f(m,n) = f(m-1,n-1)+1
    2.如果 ym != yn,那么公共子序列是: 
    X(m-1)与 Y(n)的最长公共子序列 
    X(m)与 Y(n-1)的最长公共子序列
    之间较长的那个
    则f(m, n) = max{ f(m-1, n), f(m, n-1) }
    PS:需要用连个FOR循环,将表从左上往右下遍历。最后右下就是结果
     
    int max(int a,int b){
        if(a>=b)return a;
        else return b;
    }
    int helper(int **f,int i,int j){
        if(f[i][j]==-1){
            int a,b;
            if(f[i-1][j]!=-1)a=f[i-1][j];
            else a=helper(f,i-1,j);
            if(f[i][j-1]!=-1)b=f[i][j-1];
            else b=helper(f,i,j-1);
            f[i][j]=max(a,b);
            return f[i][j];
        }else{
            return f[i][j];
        }
    }
     
    int final(char *c1,char *c2,int n1,int n2){
        int* f[n1+1];
        for(int i=0;i<=n1;++i){
            f[i]=new int[n2+1];
        }
        for(int i=0;i<=n1;++i){
            for(int j=0;j<=n2;++j) f[i][j]=-1;
        }
        for(int i=0;i<=n1;++i){
            f[i][0]=0;
        }
        for(int i=0;i<=n2;++i){
            f[0][i]=0;
        }
        for(int i=1;i<=n1;++i){
            for(int j=1;j<=n2;++j){
                if(c1[i-1]==c2[j-1]){
                    f[i][j]=helper(f,i-1,j-1)+1;
                }else helper(f,i,j);
            }
        }
        return f[n1][n2];
    }

    第五十七题:用两栈实现队列

    一盏用来存放,一盏用来弹出。栈具有翻转顺序的性质,两个栈就刚刚是顺序的队列性质了。
     
    第五十九题:设计不能被继承的类
    方法1:把构造函数和析构函数声明为私有。使用静态函数来new和delete来新建。

    方法2:

    class Helper{
        friend class noSon;//这里其实应该用模板T代替noson,但codeblock不知为何不支持
    private:
        Helper(){}
        ~Helper(){}
    };
     
    class noSon:virtual public Helper{//使用虚继承是希望子类直接调用最底层父类的构造函数。从而继承noson的子类调用Help的私有构造函数
    public:                                          //这样noson就不能被继承。如果没有virtual,则子类会正常调用noson的共有构造函数。
        noSon(){cout<<"noSon is created!";}//而noson在调用helper的构造函数(因为是友元),从而可以使用。
    };

    虚继承:普通继承时,子类只可以调用直接父类的构造函数。而虚继承时,子类可以调用所有父类的构造函数详细看源代码

    虚继承时为了解决多继承的“二义性”问题。 例如B继承A,C也继承A,D继承B,C。则D含有2个A的实例。调用了2次A的构造函数。
    更严重的是造成“二义性”,就是通过D调用A的函数或者成员时,由于有2个A实例,到底调用哪个?而使用虚继承时则只有一个A实例

    第六十题:O(1)时间删除单链表节点

    传统方法是从链表头节点开始遍历,找到需要删除的节点的前一个节点,然后把这个节点与要删的后一个节点相连。
    新的方法是,把要删的后一个节点的值复制给要删的节点,然后删除后一个节点。这样就不需要遍历了。如要删最后一个节点则按传统方法,总体的平均复杂度也是O(1)
  • 相关阅读:
    请求转发和请求重定向的区别
    查看电脑连过的WiFi密码
    linux mysql不能远程登录
    map的遍历方法
    ________________springbootのMybatis
    ________________springbootのTest
    ________________springbootの自定义starter
    ________________springbootのAOP
    ________________springbootのjdbc、事物
    ________________初学springboot14
  • 原文地址:https://www.cnblogs.com/iyjhabc/p/2986030.html
Copyright © 2020-2023  润新知