微软十五道面试题

1. 有一个整数数组,请求出两两之差绝对值最小的值, 记住,只要得出最小值即可,不需要求出是哪两个数。

思路:若有a[n]个数 构造b[n] 其中 b[i] = a[i] - a[i -1]   这样a[n]中任意两个数之差 就可以用 b[i] +...+b[j] = (a[i]-a[i-1])+(a[i+1]-a[i])..+(a[j]-a[j-1]) = a[j]-a[i-1] 

因此 再利用最大连续子序列和的类似方法O(n) 即可求出  (还是有问题 当数组为 {1,20,200,16,1}这种情况时 )

int GetMinAbsoluteSubsequence(int B[],int begin,int nLen)
{
    int nGlobal=INT_MAX;
    int nSuffix=0;

    for(int i=begin; i<nLen; i++)
    {
        nSuffix+=B[i];
         if(abs(nSuffix)<abs(nGlobal))
         {
             nGlobal=nSuffix;
         }
        if(i+1<nLen)
        {
            if(nSuffix*B[i+1]>0)             //何时清零 ?
                nSuffix=0;
        }
     }
     return abs(nGlobal);
}

2. 写一个函数,检查字符是否是整数,如果是,返回其整数值。(或者:怎样只用4行代码编写出一个从字符串到长整形的函数?)

思路:按位递归处理 每次处理最后一位 直到结束 ~~ 注意考虑第一个字符为负数的情况

int str2int(char* pstr,int len)
{
    if (len > 1)
    {
        return pstr[0] == '-'?str2int(pstr,len - 1)*10 - (pstr[len - 1] - '0'):str2int(pstr,len - 1)*10 + (pstr[len - 1] - '0');
    }
    else
        return pstr[0] == '-'?0:pstr[0] - '0';
}

3、给出一个函数来输出一个字符串的所有排列。

思路: DFS  排列

//num[] 为可用的字符  ch[i]用来标记是否已经放入num[i]
void dfs(char ar[],int len,bool ch[],char num[],int dp)
{
    if (dp == len)                            
    {
        for (int i = 0 ; i< len;++i)
        {
            cout<<ar[i];
        }
        cout<<endl;
        return;
    }
    for (int i = 0;i < len;++i)
    {
        if (!ch[i])     //如果num[i]还没放入
        {
            ch[i] = true;
            ar[dp] = num[i];
            dfs(ar,len,ch,num,dp + 1);
            ch[i] = false;
        }
    }
}

 4、请编写实现malloc()内存分配函数功能一样的代码。 
给出一个函数来复制两个字符串A和B。字符串A的后几个字节和字符串B的前几个字节重叠。

5、怎样编写一个程序,把一个有序整数数组放到二叉树中?

6、怎样从顶部开始逐层打印二叉树结点数据?请编程。  

思路:二叉树的层次遍历 利用队列 记录层次

void print_tree(NODE* T)
{
    if (T == NULL)
    {
        cout<<"Empty Tree!"<<endl;
        return;
    }
    int cenci = 1;
    queue<NODE*>stn;
    queue<int>cst;
    stn.push(T);
    cst.push(cenci);
    NODE* temp = NULL;
    while (!stn.empty())
    {
        temp = stn.front();
        stn.pop();
        if (cst.front() == cenci)
        {
            cout<<temp->val<<' ';
        }
        else
        {
            cenci = cst.front();
            cout<<endl<<temp->val<<' ';
        }
        cst.pop();
        if (temp->lchild)
        {
            stn.push(temp->lchild);
            cst.push(cenci + 1);
        }
        if (temp->rchild)
        {
            stn.push(temp->rchild);
            cst.push(cenci + 1);
        }
    }
}

7、怎样把一个链表掉个顺序(也就是反序,注意链表的边界条件并考虑空链表)?

Nod* rev(Nod* head)        //head 当前
{
    Nod* pre =NULL;     //pre  前续  
    Nod* nex = NULL;   //nex  后续
    while (head)
    {
        nex = head->next;
        head->next = pre;
        pre = head;
        head = nex;
    }
    return pre;
}

8、请编写能直接实现int atoi(const char * pstr)函数功能的代码。

int atoi_m(const char* p,int len)
{
    if (len == 0)
    {
        return 0;
    }
    if (len > 1)
    {
        return p[0]=='-'?atoi_m(p,len - 1)*10 - p[len - 1]+'0':atoi_m(p,len - 1)*10 + p[len - 1] - '0';
    }
    else
        return p[0] == '-'?0:p[0] - '0';
}

9、编程实现两个正整数的除法
编程实现两个正整数的除法,当然不能用除法操作符。
// return x/y.
int div(const int x, const int y) 

int divv(const int x,const int y)
{
    int x_temp = x;
    int anw = 0;
    int multi;
    while (x_temp >= y)
    {
        multi = 1;
        while (y*multi <= (x_temp>>1)) //y*m <= x/2  m翻倍
        {
            multi = multi<<1;
        }
        anw += multi;
        x_temp -= y*multi;       //减去已有的
    }
    return anw;
}

10、在排序数组中,找出给定数字的出现次数 比如 [1, 2, 2, 2, 3] 中2的出现次数是3次

思路:二分查找 找到后左右遍历 这样复杂度为O(n + s)  ; 如果需要多次查找 还是建立hash比较好

   网上有思路说 用二分查找起始点和终点的位置  再相减即可

View Code
int b_search(int ar[],int first,int last,int val) //二分查找 找不到返回-1
{
    if (first < last)
    {
        int mid = (first + last)/2;
        if (ar[mid] == val)
        {
            return mid;
        }
        else if (ar[mid] < val)
        {
            return b_search(ar,mid + 1,last,val);
        }
        else
            return b_search(ar,first,mid - 1,val);
    }
    else if (first == last)
    {
        return ar[last] == val?last:-1;
    }
    return -1;
}
int getTim(int ar[],int n,int k)    //计算k出现的次数
{
    int temp = b_search(ar,0,n-1,k);
    if (temp == -1)
    {
        return 0;
    } 
    else
    {
        int num = 1;
        int pos = temp + 1;
        while (pos < n&&ar[pos++] == k)  //向后找
        {
            ++num;
        }
        pos = temp - 1;
        while (pos >= 0&&ar[pos--] == k) //向前找
        {
            ++num;
        }
        return num;
    }
}
        int* pos1 = lower_bound(ar,ar + n,k);
        int* pos2 = upper_bound(ar,ar + n,k);
        cout<<pos2 - pos1<<endl;

 11、平面上N个点,每两个点都确定一条直线,求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。

 3个点A,B,C,把它们的按x坐标排序。假设排序后的顺序是ABC,那么有两种情况:

1.ABC共线,则k(AB)=k(BC)=k(AC)
2.ABC不共线,则ABC将形成一个三角形,那么k(AC)<max(k(AB), k(BC))
其中k()表示求斜率。
所以程序的基本步骤就是:
1.N个点按x坐标排序。
2.遍历,求相邻的两个点的斜率,找最大值。
时间复杂度Nlog(N)
 
12、一个整数数列,元素取值可能是0~65535中的任意一个数,相同数值不会重复出现。0是例外,可以反复出现。
请设计一个算法,当你从该数列中随意选取5个数值,判断这5个数值是否连续相邻。
注意:
- 5个数值允许是乱序的。比如: 8 7 5 0 6
- 0可以通配任意数值。比如:8 7 5 0 6 中的0可以通配成9或者4
- 0可以多次出现。
- 复杂度如果是O(n2)则不得分。

 思路: 排序 如 8 7 5 0 6 排序后: 0 5 6 7 8  ; 得到0的个数 N0,非0的个数为 N1 ,非0个序列首尾 5 和 8,非0序列的长度 LEN = arr[4] - ar[非0第一个] + 1

若LEN -  N1<= N则可以,否则 不能组成序列  O(NlogN) + O(N)

    sort(arr,arr + n);    //首先排序
    int pos = 0;          //pos 为0的个数
    int num = arr[pos];          
    while (!num)              //num为第一个非0值
    {
        ++pos;
        num = arr[pos];
    }
    if (arr[4] - num + 1 - 5 + pos<= pos) //非0值序列长度-已有元素 <= 0的元素
    {
        cout<<"CAN"<<endl;
    }
    else
        cout<<"No"<<endl;

 13、设计一个算法,找出二叉树上任意两个结点的最近共同父结点。复杂度如果是O(n2)则不得分。

 思路:网上标准答案是LCA的算法  http://kmplayer.iteye.com/blog/604518

  不过感觉对本人来说理解有点困难,如果真遇到面试这种题,O(n)的方法也不是没有,那就是找到两个结点的祖先序列VecA VecB,  其中,长的序列的多出的部分可以抛弃,因为

一定不是公共的部分,(举例,VecA > VecB , 则 VecA的前几个元素都可以删除),然后查找VecA和VecB的第一个相同元素就是最近公共祖先.

bool dfs(NODE* head,int val,vector<NODE*> &vp)//找val节点的祖先序列
{
    if (head == NULL)
    {
        return false;
    }
    if (head->val == val)
    {
        vp.push_back(head);
        return true;
    }
    if (dfs(head->lchild,val,vp))
    {
        vp.push_back(head);
        return true;
    }
    else if (dfs(head->rchild,val,vp))
    {
        vp.push_back(head);
        return true;
    }
    else
        return false;
}
                      // 1 2 4 -1 -1 5 -1 -1 3 6 7 -1 9 -1 -1 8 -1 -1 -1
int main()
{
    NODE* head = creat_tree();
//    cenci(head);
//    preDis(head);
    int a = 9, b = 8;
    vector<NODE*>vp;
    dfs(head,a,vp);
    vector<NODE*>vp2;
    dfs(head,b,vp2);
    int len = abs(int(vp.size() - vp2.size()));
    if (vp.size() > vp2.size())
    {
        while (len--)
        {
            vp.erase(vp.begin());
        }
    }
    else
    {
        while (len--)
        {
            vp2.erase(vp2.begin());
        }
    }
    int pos = 0;
    while (vp[pos] != vp2[pos])
    {
        ++pos;
    }
    cout<<vp[pos]->val<<endl;

14、一棵排序二叉树,令 f=(最大值+最小值)/2, 设计一个算法,找出距离f值最近、大于f值的结点。复杂度如果是O(n2)则不得分。

  思路: 优化GP: 中序遍历,找到第一个大于f的节点即是 (因为一定存在比f大的数)

 

bool have = false;       //是否找到大于f的数
int f = 4;                   //f
void midDis(NODE* head) //中序遍历
{
    if (have||head == NULL)
    {
        return;
    }
    midDis(head->lchild);
    if (head->val > f)
    {
        cout<<head->val<<endl;
        have = true;
        return;
    }
    midDis(head->rchild);
}

15、一个整数数列,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。  复杂度最好是O(n),如果是O(n2)则不得分。

思路: 位图排序?然后扫描 时间复杂度是O(n) 但是需要O(n)的空间

    bool arr[n + 1];         //位图
    memset(arr,0,sizeof(arr));
    for (int i = 0;i < m;++i)  //位图排序
    {
        arr[ar[i]] = true;
    }
    int i = 1, j = n;     //起点和终点(最小值 最大值)
    int ff = 1 + n;
    while (i < j)         //O(n)遍历求和
    {
        if (i + j < ff)
            ++i;
        else if (i + j > ff)
            --j;
        else
        {
            if (arr[i]&&arr[j])
            {
                cout<<i<<"+"<<j<<"="<<ff<<endl;
            }
            ++i;
            --j;
        }
    }

 

原文地址:https://www.cnblogs.com/itachi7/p/2679554.html