面试总结1

转载自:http://blog.csdn.net/v_july_v/article/details/68702511.把二元查找树转变成排序的双向链表
题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
10
/ \
6 14
/ \ / \
4 8 12 16
转换成双向链表
4=6=8=10=12=14=16。

首先我们定义的二元查找树节点的数据结构如下:

struct BSTreeNode
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
ANSWER:
This is a traditional problem that can be solved using recursion. 
For each node, connect the double linked lists created from left and right child node to form a full list.
/**
 * @param root The root node of the tree
 * @return The head node of the converted list.
 */
BSTreeNode * treeToLinkedList(BSTreeNode * root) {
  BSTreeNode * head, * tail;
  helper(head, tail, root);
  return head;
}

void helper(BSTreeNode *& head, BSTreeNode *& tail, BSTreeNode *root) {
  BSTreeNode *lt, *rh;
  if (root == NULL) {
    head = NULL, tail = NULL;
    return;
  }
  helper(head, lt, root->m_pLeft);
  helper(rh, tail, root->m_pRight);
  if (lt!=NULL) {
    lt->m_pRight = root;
    root->m_pLeft = lt;
  } else  {
    head = root;
  }
  if (rh!=NULL) {
    root->m_pRight=rh;
    rh->m_pLeft = root;
  } else {
    tail = root;
  }
}


3.求子数组的最大和

题目:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。
ANSWER: 
A traditional greedy approach.
Keep current sum, slide from left to right, when sum < 0, reset sum to 0.

int maxSubarray(int a[], int size) {
  if (size<=0) error(“error array size”);
  int sum = 0;
  int max = - (1 << 31);
  int cur = 0;
  while (cur < size) {
    sum += a[cur++];
    if (sum > max) {
      max = sum;
    } else if (sum < 0) {
      sum = 0;
    }
  }
  return max;
}

5.查找最小的k 个元素
题目:输入n 个整数,输出其中最小的k 个。
例如输入1,2,3,4,5,6,7 和8 这8 个数字,则最小的4 个数字为1,2,3 和4。
ANSWER:
This is a very traditional question...
O(nlogn): cat I_FILE | sort -n | head -n K
O(kn): do insertion sort until k elements are retrieved.
O(n+klogn): Take O(n) time to bottom-up build a min-heap. Then sift-down k-1 times.
So traditional that I don’t want to write the codes...
Only gives the siftup and siftdown function.
/**
 *@param i the index of the element in heap a[0...n-1] to be sifted up
void siftup(int a[], int i, int n) {
  while (i>0) {
    int j=(i&1==0 ? i-1 : i+1);
    int p=(i-1)>>1;
    if (j<n && a[j]<a[i]) i = j;
    if (a[i] < a[p]) swap(a, i, p);
    i = p;
  }  
}
void siftdown(int a[], int i, int n) {  
  while (2*i+1<n){
    int l=2*i+1;
    if (l+1<n && a[l+1] < a[l]) l++;
    if (a[l] < a[i]) swap(a, i, l);
    i=l;
  }
}

颠倒一个字符串。优化速度。优化空间。
void reverse(char *str) {
  reverseFixlen(str, strlen(str));
}
void reverseFixlen(char *str, int n) {
  char* p = str+n-1;
  while (str < p) {
    char c = *str;
    *str = *p; *p=c;
  }    
}

★假设你有一个用1001 个整数组成的数组,这些整数是任意排列的,但是你知道所有的整数都在1 到1000(包括1000)之间。此外,除一个数字出现两次外,其他所有数字只出现一次。假设你只能对这个数组做一次处理,用一种算法找出重复的那个数字。如果你在运算中使用了辅助的存储方式,那么你能找到不用这种方式的算法吗?
ANSWER:
Sum up all the numbers, then subtract the sum from 1001*1002/2.
Another way, use A XOR A XOR B = B: 
int findX(int a[]) {
  int k = a[0]; 
  for (int i=1; i<=1000;i++)
    k ~= a[i]~i;
  }
  return k;
}

★不用乘法或加法增加8 倍。现在用同样的方法增加7 倍。
ANSWER:
n<<3;
(n<<3)-n;

第9题-----------------------------------
判断整数序列是不是二元查找树的后序遍历结果
题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。
如果是返回true,否则返回false。
例如输入5、7、6、9、11、10、8,由于这一整数序列是如下树的后序遍历结果:
    8
   / /
  6  10
/ / / /
5 7 9 11
因此返回true。
如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。

bool verifySquenceOfBST(int squence[], int length)
{
      if(squence == NULL || length <= 0)
            return false;

      // root of a BST is at the end of post order traversal squence
      int root = squence[length - 1];

      // the nodes in left sub-tree are less than the root
      int i = 0;
      for(; i < length - 1; ++ i)
      {
            if(squence[i] > root)
                  break;
      }

      // the nodes in the right sub-tree are greater than the root
      int j = i;
      for(; j < length - 1; ++ j)
      {
            if(squence[j] < root)
                  return false;
      }

      // verify whether the left sub-tree is a BST
      bool left = true;
      if(i > 0)
            left = verifySquenceOfBST(squence, i);

      // verify whether the right sub-tree is a BST
      bool right = true;
      if(i < length - 1)
            right = verifySquenceOfBST(squence + i, length - i - 1);

      return (left && right);
}

第10 题
翻转句子中单词的顺序。
题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。
句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。
例如输入“I am a student.”,则输出“student. a am I”。
#include<iostream>
#include<string>
using namespace std;

class ReverseWords{
public:
    ReverseWords(string* wo):words(wo){}
    void reverse_()
    {
        int length=words->size();
        int begin=-1,end=-1;
        for(int i=0;i<length;++i){
            if(begin==-1&&words->at(i)==' ')
                continue;
            if(begin==-1)
            {
                begin=i;
                continue;
            }
            if(words->at(i)==' ')
                end=i-1;
            else if(i==length-1)
                end=i;
            else 
        continue;
            reverse__(begin,end);    //1.字母翻转
            begin=-1,end=-1;           
        }
        reverse__(0,length-1);       //2.单词翻转
    }

private:
    void reverse__(int begin,int end)   //
    {
        while(begin<end)               
    {
            char t=words->at(begin);
            words->at(begin)=words->at(end);
            words->at(end)=t;
            ++begin;
            --end;
        }
    }
    string* words;
};


int main(){
    string s="I  am a student.";
    ReverseWords r(&s);
    r.reverse_();
    cout<<s<<endl;
   
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值