面试题(二)

来源:互联网 发布:常用路由选择算法 编辑:程序博客网 时间:2024/04/29 21:14

注:不喜勿喷

//21.合并两个排序的链表//输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增的,例如,链表1和//链表2,则合并之后的升序链表如链表3所示,节点定义如下:struct ListNode{    int _value;    ListNode* _next;};ListNode* merge(ListNode* phead1,ListNode* phead2){    if(phead1 == nullptr)        return phead2;    if(phead2 == nullptr)        return phead1;    ListNode* newroot = nullptr;    if(phead1->_value < phead2->_value)    {        newroot = phead1;        newroot->_next = merge(phead1->_next,phead2);    }    else    {        newroot = phead2;        newroot->_next = merge(phead1,phead2->_next);    }    return newroot;}//22.树的子结构//输入两棵二叉树A和B,判断B是不是A的子结构。二叉树结点的定义如下:struct BinaryTreeNode{    double _value;    BinaryTreeNode* _left;    BinaryTreeNode* _right;};typedef BinaryTreeNode Node;bool BisAchildTree(Node* root1, Node* root2){    bool result = false;    if(root1 != nullptr && root2 != nullptr)    {        if(Equal(root1->_value,root2->_value))        {            result = IsAhasB(root1,root2);        }        if(!result)            result = BisAchildTree(root1->_left,root2);        if(!result)            result = BisAchildTree(root1->_right,root2);    }    return result;}bool IsAhasB(Node* root1,Node* root2){    if(root1 == nullptr)        return false;    if(root2 == nullptr)        return true;    bool resultleft = false;    bool resultright = false;    if(!Equal(root1->_value,root2->_value))    {        return false;    }    resultleft = IsAhasB(root1->_left,root2->_left);    resultright = IsAhasB(root1->_right,root2->_right);    return resultleft && resultright;}bool Equal(double x,double y){    if((x - y) > - 0.0000001 && (x -y) < 0.0000001)    {        return true;    }    return false;}//23.二叉树的镜像//请完成一个函数,输入一棵二叉树,该函数输出它的镜像,二叉树的节点定义如下:struct BinaryTreeNode2{    int _value;    BinaryTreeNode2* _left;    BinaryTreeNode2* _right;};typedef BinaryTreeNode2 Node;void BinaryMirror(Node* root){    if(nullptr == root)        return;    swap(root->_left,root->_right);    BinaryMirror(root->_left);    BinaryMirror(root->_right);}//24.对称的二叉树//实现一个函数,用来判断一棵二叉树是不是对称的,如果一棵二叉树和它的镜像一样,那么它是对称的;bool IsSymmetrical(Node* root){    return _IsSymmetrical(root,root);}//针对前序遍历:根左右//对称序列的谦虚遍历是:根右左bool _IsSymmetrical(Node* root1,Node* root2){    if(root1 == nullptr && root2 == nullptr)        return true;    if(root1 == nullptr || root2 == nullptr)        return false;    if(root1->_value != root2->_value)    {        return false;    }    return _IsSymmetrical(root1->_left,root2->_right)        && _IsSymmetrical(root1->_right,root2->_left);}//25.顺时针打印矩阵//输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,如,输入如下矩阵:// 1   2   3   4// 5   6   7   8// 9  10  11  12//13  14  15  16//依次打印出来的顺序是:1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10void _PrintMatre(int* arr,int row,int col,int start);void PrintMatRe(int* arr,int row,int col){    if(nullptr == arr || row <= 0 || col <= 0)        return;    int start = 0;    while(row > start*2 && col > start*2)    {        _PrintMatre(arr,row,col,start);        ++start;    }}void _PrintMatre(int* arr,int row,int col,int start){    int endRow = row - 1 - start;    int endCol = col - 1 - start;    //从左往右    if(start <= endCol)    {        for(int i = start; i <= endCol; i++)        {            cout<<arr[start*col+i]<<" ";        }    }    //从上到下    if(start <= endRow)    {        for(int i = start+1; i <= endRow; i++)        {            cout<<arr[i*col+endCol]<<" ";        }    }    //从右往左,防止出现一列,一行的现象    if(start < endCol && start < endRow)    {        for(int i = endCol-1; i >= start; --i)        {            cout<<arr[endRow*col+i]<<" ";        }    }    //从下到上,防止出现一列,一行的现象    if(start < endCol && start < endRow)    {        for(int i = endRow-1; i > start; --i)        {            cout<<arr[i*col+start]<<" ";        }    }}//26.包含min函数的栈//定义一个栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数,在该栈中,调用//min,push及pop的时间复杂度为O(1)//分析:栈:先进后出,尾插尾删,数据结构不能改变//必须保证我们每次在执行push和pop操作的时候还能知道栈里面的最小元素,所以需要引进辅助栈template <class T>class Stack{private:    T* _arr;    int _size;    int _capacity;public:    Stack()        :_arr(NULL),_size(0),_capacity(0)    {}    ~Stack()    {        if(_arr != NULL)        {            free(_arr);        }        _arr = NULL;        _size = _capacity = 0;    }    void Push(const T& value)    {        checkcapacity();        _arr[_size] = value;        ++_size;    }    void Pop()    {        if(_size == 0)            return;        --_size;    }    void checkcapacity()    {        if(_size >= _capacity)        {            _capacity = _capacity*2+1;            T* arr = malloc(_capacity * sizeof(T));            for(int i = 0; i < _size; i++)            {                arr[i] = _arr[i];            }            free(_arr);            _arr = arr;        }    }};//27.栈的压入,弹出序列//输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否是该栈的弹出序列,假设//压入栈的所有数字均不相等,例如,序列{1,2,3,4,5}是某栈的压栈序列,序列{4,5,3,2,1}//是该栈序列对应得一个弹出序列,但是{4,3,5,1,2}就不可能是该压栈序列的弹出序列bool IsPopOrder(int* arr1,int *arr2,int length){    assert(arr1 && arr2);    if(length <= 0)        return false;    int* p1 = arr1;    int* p2 = arr2;    stack<int> _st;    int j = 0;    int i = 0;    for(; i < length; i++)    {        while(_st.empty() || _st.top() != p2[i])        {            if(j == length)            {                break;            }            _st.push(p1[j]);            ++j;        }        if(_st.top() != p2[i])        {            break;        }        cout<<_st.top()<<" ";        _st.pop();    }    cout<<endl;    if(_st.empty() && i == length)        return true;    return false;}//28.从上到下打印二叉树//不分行从上到下打印二叉树:从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序//打印,例如:输入,打印;,二叉树定义如下:struct BinaryTreeNode{    int _value;    BinaryTreeNode* _left;    BinaryTreeNode* _right;};//分析:创建一个队列,按照先进先出的队列层序遍历访问每一个节点typedef BinaryTreeNode Node;#include<queue>void LevelOrder(Node* root){    assert(root);    queue<Node*> q;    q.push(root);    while(!q.empty())    {        Node* cur = q.top();        cout<<cur->_value<<" ";        if(cur->_left != NULL)        {            q.push(cur->_left);        }        if(cur->_right != NULL)        {            q.push(cur->_right);        }        q.pop();    }}#include <queue>//29.分行从上到下打印二叉树void LevelOrderAndLine(Node* root){    assert(root);    queue<Node*> q;    q.push(root);    int curlevel = 1;    int nextlevel = 0;    while(!q.empty())    {        Node* cur = q.front();        cout<<cur->_value<<" ";        if(cur->_left != NULL)        {            q.push(cur->_left);            ++nextlevel;        }        if(cur->_right != NULL)        {            q.push(cur->_right);            ++nextlevel;        }        q.pop();        if(--curlevel == 0)        {            cout<<endl;            curlevel = nextlevel;            nextlevel = 0;        }    }}//30.打印之字形二叉树//上到右,右到左,左到右,右到左,以此类推;//分析,两个栈一个存放节点顺序是左右---偶数层,一个存放节点顺序是右左---奇数层#include <stack>void LevelOrderAndLineZHI(Node* root){    assert(root);    stack<Node*> stack[2];    int current = 0;//奇数层    int next = 1;//偶数层    stack[current].push(root);    while(!stack[0].empty() || !stack[1].empty())    {        Node* cur = stack[current].top();        cout<<cur->_value<<" ";        stack[current].pop();        if(current == 0)        {            if(cur->_left != NULL)            {                stack[next].push(cur->_left);            }            if(cur->_right != NULL)            {                stack[next].push(cur->_right);            }        }        else//current == 1,当前层在偶数层        {            if(cur->_right != NULL)            {                stack[next].push(cur->_right);            }            if(cur->_left != NULL)            {                stack[next].push(cur->_left);            }        }        if(stack[current].empty())        {            cout<<endl;            current = 1 - current;            next = 1 - next;        }    }}//31.二叉搜索树的后序遍历序列//输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果,如果是则返回true,否则返回//false,假设输入的数组的任意两个数字都互不相同,例如输入数组{5,7,6,9,11,10,8},则返回//true,因为这个证书序列是图中二叉搜索树的后序遍历结果,如果输入的数组是{7,4,6,5},则由于//没有那颗二叉搜索树的后序遍历结果是这个序列,因此返回false;//分析:后序遍历--->左右根,根节点是最后一个节点,而且二叉搜索树,左子树比根小//右子树比根大bool IsBackOrder(int* arr,int len){    if(arr == NULL && len <= 0)    {        return false;    }    int* root = arr + len - 1;    int i = 0;    for(; i < len-1; i++)    {        if(arr[i] > *root)        {            break;        }    }    int j = i;    for(; j < len-1; j++)    {        if(arr[j] < *root)        {            return false;        }    }    bool IsLEFT = true;    if(i > 0)    {        IsLEFT = IsBackOrder(arr,i);    }    bool IsRIGHT = true;    if(j < len-1)    {        IsRIGHT = IsBackOrder(arr+i,len-i-1);    }    return IsLEFT && IsRIGHT;}//32.二叉树中和为某一路径的值void _PathFind(Node* root,const int key,int& value,stack<int>& q){    if(nullptr == root)        return;    q.push(root->_value);    value += root->_value;    if(value == key && root->_left == NULL && root->_right == NULL)    {        while(!q.empty())        {            cout<<q.top()<<" ";            q.pop();        }    }    if(root->_left != NULL)    {        _PathFind(root->_left,key,value,q);    }    if(root->_right != NULL)    {        _PathFind(root->_right,key,value,q);    }    value -= q.top();    q.pop();}void PathFind(Node* root,const int key){    assert(root);    int value = 0;    stack<int> q;    _PathFind(root,key,value,q);}//用vector做可以将所有的访问完全//33.复杂链表的复制过程://请实现一个函数复制一个复杂链表,在复杂链表中,每个节点除了有一个next指针指向下一个节点//还有一个sib指针指向任意一个节点或者NULL,节点定义如下:struct ComplexListNode{    int _value;    ComplexListNode* _next;    ComplexListNode* _pSib;    ComplexListNode(int value)        :_value(value),_next(NULL),_pSib(NULL)    {}};//分析:分三步走的方法:第一步复制所有的节点,第二步复制所有的随机下一个节点的位置路径,//第三步拆分链表//第一步:复制所有的当前结点到下一个指向typedef ComplexListNode Node;Node* CopyComplexList(Node* root){    assert(root);    CopyComplexNode(root);    CopyComplexPath(root);    Node* newRoot = ComplexListCut(root);    return newRoot;}void CopyComplexNode(Node* root){    Node* cur = root;    Node* next = cur;    while(cur)    {        next = cur->_next;        Node* newcur = new Node(cur->_value);        cur->_next = newcur;        newcur->_next = next;        cur = next;    }}void CopyComplexPath(Node* root){    Node* cur = root;    Node* pnext = cur;    Node* next = cur;    while(cur)    {        next = cur->_next;        pnext = cur->_pSib;        if(pnext != NULL)        {            next->_pSib = pnext->_next;        }        cur = next->_next;    }}Node* ComplexListCut(Node* root){    Node* curS = root;    Node* curD = root->_next;    Node* newRoot = curD;    Node* cur = curD->_next;    if(NULL == cur)    {        root->_next = NULL;        return newRoot;    }    int count = 0;    while(cur)    {        if((++count) % 2 == 1)//奇数        {            curS->_next = cur;            curS = curS->_next;        }        else        {            curD->_next = cur;            curD = curD->_next;        }        cur = cur->_next;    }    return newRoot;}//34.二叉搜索树与双向链表//输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表,要求不能创建任何新的节点,//只能调整树种节点指针的指向,二叉树节点定义如下struct BinaryTreeNode{    int _value;    BinaryTreeNode* _left;    BinaryTreeNode* _right;};//对于搜索二叉树而言,要想要生成一个有序的节点就是中序遍历---左根右typedef BinaryTreeNode Node;Node* BinaryTreeNodeToList(Node* root){    assert(root);    Node* prev = NULL;    ConvertNode(root,prev);    Node* cur = root;    while(cur != nullptr && cur->_left == nullptr)    {        cur = cur->_left;    }    return cur;}void ConvertNode(Node* root, Node*& prev){    if(nullptr == root)        return;    if(root->_left != nullptr)        ConvertNode(root->_left,prev);    root->_left = prev;    if(prev != nullptr)        prev->_right = root;    prev = root;    if(root->_right != nullptr)        ConvertNode(root->_right,prev);}//35.二叉树的序列化和反序列化//36.字符串的排列//输入一个字符串,打印出该字符串中字符的所有排列,例如,输入字符串“abc”,将由abc所能//排列出来的所有字符串都打印出来;void PrintString(char* str,char* cur,int& count);void printString(char* str){    assert(str);    int count = 0;    PrintString(str,str,count);    cout<<endl<<count<<endl;}void PrintString(char* str,char* cur,int& count){    if(*cur == '\0')    {        cout<<str<<" ";        ++count;    }    else    {        for(char* ch = cur; *ch != '\0'; ++ch)        {            swap(*ch , *cur);            PrintString(str,cur+1,count);            swap(*ch , *cur);        }    }}//37.二叉搜索树的第K大节点//给定一棵二叉搜索树,请找出其中第K大的节点;//分析:利用中序遍历将二叉搜索树生成一个递增的数组,这样就可以找到第K大节点Node* GetKNode(Node* root,int& k){    if(nullptr == root)    {        return nullptr;    }    Node* Knode = GetKNode(root->left,k);    if(--k == 0)        return root;    if(Knode == nullptr)        Knode = GetKNode(root->right,k);    return Knode;}//38.输入一个整形数组,数组里有正数也有负数,数组中的一个或者连续多个整数组成一个子数组,//求所有子数组的和的最大值,要求时间复杂度是O(N);//分析:审清题意,此处的和是连续的数组中元素的和,所以我们从1开始加到最后一个数,保存当前//此时减少前的最大值,然后不停更新最大值即可#include <assert.h>int GetchildArrSum(int* arr,int length){    assert(arr && length > 0);    int maxSum = arr[0];    int prevSum = arr[0];    for(int i = 1; i < length; i++)    {        if(arr[i] < 0)        {            prevSum += arr[i];        }        else if(arr[i] > prevSum + arr[i])//此时arr[i] >= 0        {            maxSum = arr[i];            prevSum = arr[i];        }        else        {            maxSum = prevSum + arr[i];            prevSum = maxSum;        }    }    return maxSum;}//39.1~n整数中1出现的次数//题目:输入一个整数N,求1~n这n个整数的十进制表示中1出现的次数,例如:输入12,1~12这些整数//中包含1的数字有1,10,11,12,1总共出现了5次;int GetOneCount(int x){    assert(x > 0);    if(x < 10)    {        return 1;    }    int count = 1;    for(int i = 10; i <= x; i++)    {        int number = i;        while(number != 0)        {            if(number % 10 == 1)                ++count;            number /= 10;        }    }    return count;}//40.数组中数字出现的次数//题目:数组中只出现一次的两个数字//一个整型数组里除两个数字之外,其他数字都出现了两次,请写程序找出这两个只出现一次的数字//要求时间复杂度是O(N),空间复杂度是O(1)//分析:利用异或算法-->相同的两个数之间异或的结果是0;//第一步:首先将数组中所有的数字都异或一遍,求出两个不同数的异或值;//第二步:保存上个结果的异或值,找出该值中二进制表示中第一个1出现的位置(从右往左);//第三步:将数组分成两部分,将两个不同数分别放入这辆部分然后异或得出int FindPosOne(int result);void FindTwoDiffNumber(int* arr,int length, int* num1, int* num2){    assert(arr && length > 0);    int result = 0;    for(int i = 0; i < length; i++)    {        result ^= arr[i];    }    int pos = FindPosOne(result);    result = 1 << pos;    *num1 = *num2 = 0;    for(int i = 0; i < length; i++)    {        if(arr[i] & result)        {            *num1 ^= arr[i];        }        else        {            *num2 ^= arr[i];        }    }}int FindPosOne(int result){    int pos = 0;    while(((result & 1) != 1) && pos < 32)    {        result = result >> 1;           ++pos;    }    return pos;}//41.在一个数组中除了一个数字出现一次以外其余数字都出现三次,请找出那个数字;//这次不能再使用异或运算了,因为是三次,所以异或结果还是元素自己//分析:因为其余每个元素都出现了三次,那么每个元素的二进制中三次出现之和都是3的倍数,//那么所有的数字加起来除了唯一出现一次的那个数字意外都是3的倍数,所以我们使用二进制每个位置//上面的值(0/1)的个数加起来然后%3,并且记录每个位置上面的数目,这样%完以后将每个位置上面//的结果拼在一起就是所求的数的二进制值int FindOnlyOneNumber(int* arr, int length){    assert(arr && length > 0);    int num[32] = {0};    int result;    for(int i = 0; i < length; i++)    {        result = 1;        for(int j = 0; j < sizeof(num)/sizeof(num[0]); j++)        {            if((arr[i] & result) != 0)            {                num[j] += 1;            }            result = result << 1;        }    }    result = 0;    for(int i = (sizeof(num)/sizeof(num[0]))-1; i >= 0 ; --i)    {        result += num[i] % 3;        if(i != 0)        {            result = result << 1;        }    }    return result;}