大神博客笔试(转)

工作/面试/笔试 专栏收录该内容
14 篇文章 0 订阅

这些题目来自v_JULY_v大神博客:http://blog.csdn.net/v_july_v/article/details/7974418


  1. 9月11日, 京东:谈谈你对面向对象编程的认识

整理答案:

面向对象可以理解为对待每一个问题,都是首先要确定这个问题由几个本分组成,而每一个部分其实就是一个对象。然后再分别设计这些对象,最后得到整个程序。传统的程序设计多是基于功能的思想来进行考虑和设计的,而面向对象的程序设计则是基于对象的角度来考虑问题。这样做能够使得程序更加简洁,清晰。

面向对象深入理解请看这里

      2.   8月20日,金山面试,题目如下:

    数据库1中存放着a类数据,数据库2中存放着以天为单位划分的表30张(比如table_20110909,table_20110910,table_20110911),总共是一个月的数据。表1中的a类数据中有一个字段userid来唯一判别用户身份,表2中的30张表(每张表结构相同)也有一个字段userid来唯一识别用户身份。如何判定a类数据库的多少用户在数据库2中出现过?

思路1:

建立一张用户表,UserInMonth(userid)表里面只放不重复的用户Id,把(table_20110909,table_20110910,table_20110911)的用户Id放到一张User表里面userid都统一放到这个表里面去。判断的时候select count(1) from user u inner join UserInMonth um on u.userid=um.userid.

思路2:

还是怎么办都逃不过30张表的查询:
1.建立id表用来存放30张表的userid
create table id(userid varchar2(20)) 不用设主键
2.插入数据可以不去重复
insert in to id (select userid from table_20110909) 就插吧 30个挨个插
现在id表已经具备30天所有userid了
现在有两种选择 
3.1把表id数据导出再导入到数据库1就可以查了
select distinct userid from a where userid in(select userid from id)
或者3.2 数据库1与数据库2建立连接 用@实现查询
select distinct userid from a where userid in(select userid from id@数据库2)

其实两种操作都差不多,都是将30张表数据提取出来,再与a中数据比较,考数据库操作(我是一点不会啊,该恶补了)。

      3.   百度实习笔试题(2012.5.6)


  1、 一个单词单词字母交换,可得另一个单词,如army->mary,成为兄弟单词。提供一个单词,在字典中找到它的兄弟。描述数据结构和查询过程。

思路总结:

既可以用素数乘积法,也可用hash判别法,即逐个将一个字符串hash到另一个字符串的hash表中,全中则true,否则false。

关于这类试题请看程序员编程艺术:第二章、字符串是否包含及匹配/查找/转换/拷贝问题


2、线程和进程区别和联系。什么是“线程安全”。

答案总结:

(1)定义:
一、进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。
二、线程是进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),一个线程可以创建和撤销另一个线程;

进程和线程的关系:
(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(3)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
(4)处理机分给线程,即真正在处理机上运行的是线程。
(5)线程是指进程内的一个执行单元,也是进程内的可调度实体。
线程与进程的区别:
(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。
(4)系统开销:在创建或撤销进程的时候,由于系统都要为之分配和回收资源,导致系统的明显大于创建或撤销线程时的开销。但进程有独立的地址空间,进程崩溃后,在保护模式下不会对其他的进程产生影响,而线程只是一个进程中的不同的执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但是在进程切换时,耗费的资源较大,效率要差些。

线程的划分尺度小于进程,使得多线程程序的并发性高。

另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大的提高了程序运行效率。

线程在执行过程中,每个独立的线程有一个程序运行的入口,顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,有应用程序提供多个线程执行控制。

从逻辑角度看,多线程的意义子啊与一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

(2)线程安全

如果代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。


3、C和C++怎样分配和释放内存,区别是什么?

C使用malloc和free来创建和释放内存,C++则一般使用malloc和free库函数。

区别:

(1)new,delete是操作符,可以重载,只能在C++中使用。

(2)malloc,free是函数,可以覆盖,C,C++都可以使用

(3)new 可以调用对象的构造函数,对应的delete调用相应的析构函数。

(4)malloc仅仅分配内存,free仅仅回首内存,并不执行构造和析构函数。

(5)new,delete返回的某种数据类型的指针,malloc,free返回的是void*类型的指针。


4、一个url指向的页面里面有另一个url,最终有一个url指向之前出现过的url或空,这两种情形都定义为null。这样构成一个单链表。给两条这样单链表,判断里面是否存在同样的url。url以亿级计,资源不足以hash。

情况一:两条单链表均无环

     最简单的一种情况,由于两条链表如果交叉,他们的尾节点必然相等(Y字归并),所以只需要判断他们的尾节点是否相等即可。

情况二:两条单链表均有环

    这种情况只需要拆开一条环路(注意需要保存被设置成null的节点),然后判断另一个单链表是否仍然存在环路,如果存在,说明无交叉,反之,则有交叉的情况。

情况三:两条单链表,一条有环路,一条无环路

    这种情况显然他们是不可能有交叉的


5、 数组al[0,mid-1] 和 al[mid,num-1],都分别有序。将其merge成有序数组al[0,num-1],要求空间复杂度O(1)。

这里有个解答,经验证可行: 数组al[0,mid-1]和al[mid,num-1]是各自有序的,对数组al[0,num-1]的两个子有序段进行merge,得到al[0,num-1]整体有序


6系统设计题

百度搜索框的suggestion,比如输入“北京”,搜索框下面会以北京为前缀,展示“北京爱情故事”、“北京公交”、“北京医院”等等搜索词,输入“结构之”,会提示“结构之法”,“结构之法 算法之道”等搜索词。请问,如何设计此系统,使得空间和时间复杂度尽量低。

大神直接给出了解答:

老题,直接上Trie树Trie树的介绍见:从Trie树(字典树)谈到后缀树」+TOP Khashmap+堆,hashmap+堆 统计出如10个近似的热词,也就是说,只存与关键词近似的比如10个热词」? or  Double-array trie tree同时,StackOverflow上也有两个讨论帖子:http://stackoverflow.com/questions/2901831/algorithm-for-autocompletehttp://stackoverflow.com/questions/1783652/what-is-the-best-autocomplete-suggest-algorithm-datastructure-c-c。此外,这里有一篇关于“拼写错误检查”问题的介绍,或许对你有所启示:http://blog.afterthedeadline.com/2010/01/29/how-i-trie-to-make-spelling-suggestions/

我自己也写了一个基于Trie树的处理字符串的自动匹配系统,代码如下:

[cpp]  view plain copy
  1. /* 
  2. *   Date:2012-11-8 
  3. *       functions:Manage a system that can handle suggestion problem in serach engine. 
  4. *       While user is inputing words,the system gives a list of posible words that the user may want to input displayed in a list 
  5. *   that automaticlly. 
  6. *       The solution is to create and manage a trie tree. 
  7. *   @copyright:Chen Qin  
  8. */  
  9.   
  10. #include<iostream>  
  11. #include<vector>  
  12. #include<string>  
  13. #include<queue>  
  14. using namespace std;  
  15.   
  16. //Trie tree node  
  17. typedef struct _TrieNode  
  18. {  
  19.     string value;//word of the node  
  20.     char added_char;//the charactor added to the parent word value  
  21.     vector<struct _TrieNode*> child_list;//child pointers list  
  22.     int match_count;//the count of the words match to the node value  
  23.     int level;//level int the tree  
  24. }TrieNode,*pTrieNode;  
  25.   
  26. //Trie tree root  
  27. typedef struct _TrieRoot  
  28. {  
  29.     vector<struct _TrieNode*> child_list;//child pointers list of root of the Trie tree  
  30. }TrieTree,*pTrieTree;  
  31.   
  32. class SuggestionSystem  
  33. {  
  34. public:  
  35.     SuggestionSystem()  
  36.     {  
  37.         cout<<"construct system."<<endl;  
  38.         mpTree=new TrieTree;  
  39.         mpTree->child_list=vector<pTrieNode>();  
  40.     }  
  41.     SuggestionSystem(const vector<string> &words)  
  42.     {  
  43.         cout<<"construct system with data."<<endl;  
  44.         mpTree=new TrieTree;  
  45.         mpTree->child_list=vector<pTrieNode>();  
  46.         for(vector<string>::const_iterator it=words.begin();it<words.end();it++)  
  47.         {     
  48.             InsertWordIntoTrieTree(*it);  
  49.         }  
  50.     }  
  51.     ~SuggestionSystem()  
  52.     {  
  53.         cout<<"destruct system."<<endl;  
  54.         delete mpTree;  
  55.     }  
  56.     void CreateSystemFromWordList(const vector<string> &words);  
  57.     void DisplayTree();//display the tree node  
  58.     void FindSubsequencesOfGivenString(const string& str);//find the possible subsequencs of the given string  
  59. private:  
  60.     void InsertWordIntoTrieTree(const string &word,bool search=false);  
  61.     void InsertSubstringIntoNode(const string &word,pTrieNode pNode,bool serach=false);  
  62.     void DeleteSystem();//clear the hole system  
  63.     void FreeNode(pTrieNode pNode);//free trie node  
  64.     void VisitNode(const pTrieNode pNode);  
  65.     void DisplayTreeFromNode(const pTrieNode pNode);  
  66. private:  
  67.     pTrieTree mpTree;  
  68. };  
  69. void SuggestionSystem::CreateSystemFromWordList(const vector<string> &words)  
  70. {  
  71.     if(mpTree!=NULL)  
  72.     {  
  73.         DeleteSystem();  
  74.         mpTree=new TrieTree;  
  75.         mpTree->child_list=vector<pTrieNode>();  
  76.     }  
  77.     for(vector<string>::const_iterator it=words.begin();it<words.end();it++)  
  78.     {  
  79.         InsertWordIntoTrieTree(*it);  
  80.     }  
  81. }  
  82. void SuggestionSystem::InsertWordIntoTrieTree(const string &word,bool search)  
  83. {  
  84.     if(word.size()<=0) return;  
  85.     char c=*word.begin();  
  86.     for(vector<pTrieNode>::const_iterator it=mpTree->child_list.begin();it<mpTree->child_list.end();it++)  
  87.     {  
  88.         if((*it)->added_char==c)//alredy exits the path of the first charactor  
  89.         {  
  90.             if(word.size()==1)  
  91.             {  
  92.                 (*it)->match_count++;  
  93.                 if(search)  
  94.                 {  
  95.                     DisplayTreeFromNode(*it);  
  96.                 }  
  97.             }else  
  98.             {  
  99.                 string sub=string(word.begin()+1,word.end());  
  100.                 InsertSubstringIntoNode(sub,*it,search);  
  101.             }  
  102.             return;   
  103.         }  
  104.     }  
  105.     //create a new path of the charactor  
  106.     pTrieNode pn=new TrieNode();  
  107.     mpTree->child_list.push_back(pn);  
  108.     pn->added_char=c;  
  109.     pn->value=c;  
  110.     pn->level=1;  
  111.     if(word.size()==1)  
  112.     {  
  113.         pn->match_count=1;  
  114.     }else  
  115.     {  
  116.         pn->match_count=0;  
  117.         string sub=string(word.begin()+1,word.end());  
  118.         InsertSubstringIntoNode(sub,pn,search);  
  119.     }         
  120.               
  121. }  
  122. void SuggestionSystem::InsertSubstringIntoNode(const string &word,pTrieNode pNode,bool search)  
  123. {  
  124.     if(word.size()<=0) return;  
  125.     char c=*word.begin();  
  126.     for(vector<pTrieNode>::const_iterator it=pNode->child_list.begin();it<pNode->child_list.end();it++)  
  127.     {  
  128.         if(c==(*it)->added_char)//find the path math the first charactor of the word  
  129.         {  
  130.             if(word.size()==1)  
  131.             {  
  132.                 (*it)->match_count++;  
  133.                 if(search)  
  134.                 {  
  135.                     DisplayTreeFromNode(*it);  
  136.                 }  
  137.             }else  
  138.             {     
  139.                 string sub=string(word.begin()+1,word.end());  
  140.                 InsertSubstringIntoNode(sub,*it,search);  
  141.             }     
  142.         return;  
  143.         }  
  144.     }  
  145.     pTrieNode pn=new TrieNode();  
  146.     pNode->child_list.push_back(pn);  
  147.     pn->added_char=c;  
  148.     string val=pNode->value;  
  149.     val.push_back(c);  
  150.     pn->value=val;  
  151.     pn->level=pNode->level+1;  
  152.     if(word.size()==1)  
  153.     {  
  154.         pn->match_count=1;  
  155.     }else  
  156.     {  
  157.         pn->match_count=0;  
  158.         string sub=string(word.begin()+1,word.end());  
  159.         InsertSubstringIntoNode(sub,pn,search);  
  160.     }         
  161. }  
  162. void SuggestionSystem::FindSubsequencesOfGivenString(const string& str)//find the possible subsequencs of the given string  
  163. {  
  164.     InsertWordIntoTrieTree(str,true);  
  165. }  
  166. void SuggestionSystem::DeleteSystem()  
  167. {  
  168.     if(mpTree->child_list.size()>=1)  
  169.     {  
  170.         for(vector<pTrieNode>::iterator it=mpTree->child_list.begin();it<mpTree->child_list.end();it++)  
  171.         {  
  172.             FreeNode(*it);  
  173.         }  
  174.     }  
  175.     delete mpTree;            
  176. }  
  177. void SuggestionSystem::FreeNode(pTrieNode pNode)  
  178. {  
  179.     if(pNode->child_list.size()>=1)//has children  
  180.     {  
  181.         for(vector<pTrieNode>::iterator it=pNode->child_list.begin();it<pNode->child_list.end();it++)  
  182.         {  
  183.             FreeNode(*it);  
  184.         }  
  185.     }  
  186.     delete pNode;  
  187.     pNode=NULL;  
  188. }  
  189. void SuggestionSystem::DisplayTree()  
  190. {  
  191.     if(mpTree->child_list.size()<=0) return;  
  192.     cout<<"------the hole tree nodes display------"<<endl;  
  193.     queue<pTrieNode> que=queue<pTrieNode>();  
  194.     for(vector<pTrieNode>::iterator it=mpTree->child_list.begin();it<mpTree->child_list.end();it++)  
  195.     {  
  196.         que.push(*it);   
  197.     }  
  198.     //begin visit by queue  
  199.     cout<<"root-->"<<endl;  
  200.     int cur_lev=1;  
  201.     while(!que.empty())  
  202.     {  
  203.         pTrieNode pNode=que.front();  
  204.         que.pop();  
  205.         if(cur_lev<pNode->level)  
  206.         {  
  207.             cout<<"-->"<<endl;  
  208.             cur_lev++;  
  209.         }  
  210.         VisitNode(pNode);  
  211.         if(pNode->child_list.size()>0)  
  212.         {  
  213.             for(vector<pTrieNode>::const_iterator it=pNode->child_list.begin();it<pNode->child_list.end();it++)  
  214.             {  
  215.                 que.push(*it);            
  216.             }  
  217.         }  
  218.     }  
  219.     cout<<endl;                 
  220. }  
  221. void SuggestionSystem::DisplayTreeFromNode(const pTrieNode pNode)  
  222. {  
  223.     if(pNode==NULL) return;  
  224.     cout<<"------the found match subsequences are:------"<<endl;  
  225.     queue<pTrieNode> que=queue<pTrieNode>();  
  226.     que.push(pNode);  
  227.     //begin visit by queue  
  228.     int cur_lev=pNode->level;  
  229.     while(!que.empty())  
  230.     {  
  231.         pTrieNode pNode=que.front();  
  232.         que.pop();  
  233.         if(cur_lev<pNode->level)  
  234.         {  
  235.             cout<<"-->"<<endl;  
  236.             cur_lev++;  
  237.         }  
  238.         VisitNode(pNode);  
  239.         if(pNode->child_list.size()>0)  
  240.         {  
  241.             for(vector<pTrieNode>::const_iterator it=pNode->child_list.begin();it<pNode->child_list.end();it++)  
  242.             {  
  243.                 que.push(*it);            
  244.             }  
  245.         }  
  246.     }  
  247.     cout<<endl;                 
  248.       
  249. }  
  250.   
  251. void SuggestionSystem::VisitNode(const pTrieNode pNode)  
  252. {  
  253.     cout<<pNode->value<<" ";  
  254. }  
  255. int main(int argc,char *argv[])  
  256. {  
  257.     cout<<"developed: chen qin"<<endl;  
  258.     cout<<__DATE__<<" "<<__TIME__<<endl;  
  259.     vector<string> words;  
  260.     words.push_back("abc");  
  261.     words.push_back("bcdf");  
  262.     words.push_back("abde");  
  263.     words.push_back("bce");  
  264.     words.push_back("ad");  
  265.     words.push_back("abcf");  
  266.     words.push_back("abce");  
  267.     words.push_back("bcef");  
  268.     words.push_back("bcde");  
  269.     SuggestionSystem ss(words);  
  270.     ss.DisplayTree();  
  271.     cout<<"find subquences of ab:"<<endl;  
  272.     ss.FindSubsequencesOfGivenString("ab");  
  273.     cout<<"find subquences of bc:"<<endl;  
  274.     ss.FindSubsequencesOfGivenString("bc");  
  275.     cout<<"find subquences of abc:"<<endl;  
  276.     ss.FindSubsequencesOfGivenString("abc");  
  277.     return 0;  
  278. }  

      4.    人搜笔试题

1, 快排每次以第一个作为主元,问时间复杂度是多少?(O(N*logN))
2,T(N) = N + T(N/2)+T(2N), 问T(N)的时间复杂度是多少?  点评: O(N*logN) or O(N)?

求解数列T通项?

典型求解递归式时间复杂度题目,可以看看这里:http://www.cnblogs.com/web-application-security/archive/2012/06/15/how_to_solve_recurrences.html

3,链表相邻元素翻转,如a->b->c->d->e->f-g,翻转后变为:b->a->d->c->f->e->g。

我写了一个,复杂度为O(n)。

[cpp]  view plain copy
  1. /* 
  2. *   reverse two near nodes in a link list,for expample: 
  3. *   a->b->c->d->e->f  to  b->a->d->c->f->e     
  4. */  
  5.   
  6. #include<stdio.h>  
  7. #include<stdlib.h>  
  8. typedef struct _Node  
  9. {  
  10.     char data;  
  11.     struct _Node *next;  
  12. }Node,*pNode;  
  13.   
  14. void reverse_node(pNode pre,pNode first,pNode second);  
  15.   
  16. pNode reverse(pNode list)  
  17. {  
  18.     if(NULL==list||NULL==list->next) return list;  
  19.     pNode first=list,second=list->next,pre=NULL;  
  20.     list=list->next;  
  21.     while(first&&second)  
  22.     {  
  23.         reverse_node(pre,first,second);  
  24.         pre=first;  
  25.         first=first->next;  
  26.         if(NULL==first) break;  
  27.         second=first->next;  
  28.     }  
  29.     return list;  
  30. }  
  31. void reverse_node(pNode pre,pNode first,pNode second)  
  32. {  
  33.     if(NULL==pre)  
  34.     {  
  35.         first->next=second->next;  
  36.         second->next=first;  
  37.     }else  
  38.     {  
  39.         pre->next=second;  
  40.         first->next=second->next;  
  41.         second->next=first;  
  42.     }  
  43. }  
  44. pNode create_list()  
  45. {     
  46.     char dat;  
  47.     pNode list=NULL,last=NULL;  
  48.     while(1)  
  49.     {  
  50.         scanf("%c",&dat);  
  51.         if('#'==dat) break;  
  52.         pNode pn=(pNode)malloc(sizeof(Node));  
  53.         pn->data=dat;  
  54.         pn->next=NULL;  
  55.         if(NULL==list)  
  56.         {  
  57.             list=pn;  
  58.             last=pn;  
  59.         }else  
  60.         {  
  61.             last->next=pn;  
  62.             last=pn;  
  63.         }  
  64.     }  
  65.     return list;  
  66. }  
  67. void show_list(const pNode list)  
  68. {  
  69.     if(NULL==list) return;  
  70.     printf("list data:");  
  71.     pNode p=list;  
  72.     while(p)  
  73.     {  
  74.         printf("%c->",p->data);  
  75.         p=p->next;  
  76.     }  
  77.     printf("NULL\n");  
  78. }  
  79. int main(int argc,char *arv[])  
  80. {  
  81.     pNode list=create_list();  
  82.     printf("list before reverse.\n");  
  83.     show_list(list);  
  84.     list=reverse(list);  
  85.     printf("list after reverse.\n");  
  86.     show_list(list);  
  87. }  


4,编程题:
 一棵树的节点定义格式如下:
 struct Node{
    Node* parent;
    Node* firstChild; // 孩子节点
    Node* sibling; // 兄弟节点 
}
要求非递归遍历该树。
思路:采用队列存储,来遍历节点。与树的层序遍历相似,算法过层如下:
首先将树根节点压入队列,然后队列弹出一个节点,访问该节点,如果这个节点有兄弟节点,则将兄弟节点压入队列,有孩子节点则将孩子节点压入队列。
队列再次弹出一个节点,按照上述步骤处理,直到对空为止。

5,有N个节点,每两个节点相邻,每个节点只与2个节点相邻,因此,N个顶点有N-1条边。每一条边上都有权值wi,定义节点i到节点i+1的边为wi。
求:不相邻的权值和最大的边的集合。
解答:
动态规划求解,这里有完美解答:http://blog.csdn.net/realxie/article/details/8063885


 5.人搜面试,所投职位:搜索研发工程师:面试题回忆


 1,删除字符串开始及末尾的空白符,并且把数组中间的多个空格(如果有)符转化为1个。
我写了一个,时间复杂度为O(n):

[cpp]  view plain copy
  1. /* 
  2. *   trim the space before and after a string,and change the spaces more than two inner the stirng into one. 
  3. *   for example,input:"___a__bc__d_e__fgh_____" 
  4. *   output should be:"a_bc_d_e_fgh". 
  5. */  
  6. #include<stdio.h>  
  7. #include<stdlib.h>  
  8.   
  9. char * const trim_space(char * const str)  
  10. {  
  11.     if(NULL==str) return NULL;  
  12.     char *first=str,*last=str;  
  13.     //find the first charactor that is not a space  
  14.     while(*first=='_'&&*first!='\0') first++;  
  15.     if('\0'==*first) return "_";  
  16.     //trim the space before the string  
  17.     while('\0'!=*first) *last++=*first++;  
  18.     *last='\0';  
  19.     first=str;  
  20.     last=str;  
  21.     //trim the space inner and after the string  
  22.     while('\0'!=*first)  
  23.     {  
  24.         while('_'!=*first&&'\0'!=*first) first++;  
  25.         if('\0'==*first)  
  26.         {  
  27.             return str;  
  28.         }  
  29.         //first point to the first space inner the string  
  30.         last=first;  
  31.         while('_'==*last&&'\0'!=*last) last++;  
  32.         if('\0'==*last)//end with *(--first) and spaces  
  33.         {  
  34.             *first='\0';  
  35.             return str;  
  36.         }  
  37.         if(last-first>1)//more than one spaces  
  38.         {  
  39.             //trim spaces between first and last,leave one  
  40.             first++;  
  41.             while('\0'!=*last&&'_'!=*last)  
  42.             {  
  43.                 *first++=*last;  
  44.                 *last='_';  
  45.                 last++;  
  46.             }  
  47.             if('\0'==*last)  
  48.             {  
  49.                 *first='\0';  
  50.                 return str;  
  51.             }  
  52.         }else  
  53.         {  
  54.             first=last+1;  
  55.         }  
  56.     }  
  57.     return str;  
  58. }  
  59.   
  60. int main(int argc,char *argv[])  
  61. {  
  62.     char str[]="___a__bc__d_e__fgh_____";  
  63.     printf("original string: %s\n",str);  
  64.     printf("after trim spaces: %s\n",trim_space(str));  
  65.     char str2[]="___a_b__c_d_e__fgh";  
  66.     printf("original string: %s\n",str2);  
  67.     printf("after trim spaces: %s\n",trim_space(str2));  
  68.     char str3[]="a__bc__d_e__fgh_____";  
  69.     printf("original string: %s\n",str3);  
  70.     printf("after trim spaces: %s\n",trim_space(str3));  
  71.     return 0;  
  72. }  

2,求数组(元素可为正数、负数、0)的最大子序列和。

思路,比较简单就是连续求和,碰到和低于零再从下一个开始重新求和,我写了一个:

[cpp]  view plain copy
  1. /* 
  2. *   get the max sum of the sub sunmbers of a array. 
  3. *   for example: 5 -6 1 2 4 -9 1 3 
  4. *   the sub max sum array is 1 2 4,sum is 7 
  5. */  
  6. #include<stdio.h>  
  7.   
  8. int get_max_sub_sum(int data[],int length,int *start,int *end)  
  9. {  
  10.     int sum=0,max=0;  
  11.     int s=0,e=0,l=0,r=0;  
  12.     while(r<length)  
  13.     {  
  14.         sum+=data[r];  
  15.         if(sum>max)  
  16.         {  
  17.             max=sum;  
  18.             s=l;  
  19.             e=r;  
  20.         }  
  21.         if(sum<=0)  
  22.         {  
  23.             l=r+1;  
  24.             sum=0;  
  25.         }  
  26.         r++;  
  27.     }  
  28.     *start=s;  
  29.     *end=e;  
  30.     return max;  
  31. }  
  32.   
  33. int main(int argc,char *argv[])  
  34. {  
  35.     int d[10]={3,5,-6,1,2,4,-9,1,3};  
  36.     int s=0,e=0,max=0;  
  37.     max=get_max_sub_sum(d,9,&s,&e);  
  38.     printf("max array:\n");  
  39.     int i;  
  40.     for(i=s;i<=e;i++)  
  41.     {  
  42.         printf("%d ",d[i]);  
  43.     }  
  44.     printf("the max sum:%d\n",max);  
  45.     return 0;  
  46. }  
3,从(0,1)中平均随机出几次才能使得和超过1?(e)

思路:数学功底

让我们先来看一个更简单的问题:任取两个 0 到 1 之间的实数,它们的和小于 1 的概率有多大?容易想到,满足 x+y<1 的点 (x, y) 占据了正方形 (0, 1)×(0, 1) 的一半面积,因此这两个实数之和小于 1 的概率就是 1/2 。类似地,三个数之和小于 1 的概率则是 1/6 ,它是平面 x+y+z=1 在单位立方体中截得的一个三棱锥。这个 1/6 可以利用截面与底面的相似比关系,通过简单的积分求得:

       ∫(0..1) (x^2)*1/2 dx = 1/6

  

 
    可以想到,四个 0 到 1 之间的随机数之和小于 1 的概率就等于四维立方体一角的“体积”,它的“底面”是一个体积为 1/6 的三维体,在第四维上对其进行积分便可得到其“体积”

       ∫(0..1) (x^3)*1/6 dx = 1/24

    依此类推, n 个随机数之和不超过 1 的概率就是 1/n! ,反过来 n 个数之和大于 1 的概率就是 1 - 1/n! ,因此加到第 n 个数才刚好超过 1 的概率就是

       (1 - 1/n!) - (1 - 1/(n-1)!) = (n-1)/n!

    因此,要想让和超过 1 ,需要累加的期望次数为

       ∑(n=2..∞) n * (n-1)/n! = ∑(n=1..∞) n/n! = e

解:根据公式, ∑(n=0...∞)1/n!=e,可得∑(n=1...∞)1/n!=e-1,故原试∑(n=1..∞) n/n!=1+∑(n=2..∞) 1/(n-1)!=1+∑(n=1..∞)1/n!=1+e-1=e,大功告成!

4,链表克隆。链表的结构为: 
     typedef struct list { 
         int data; //数据字段 
     list *middle; //指向链表中某任意位置元素(可指向自己)的指针 
     list *next;//指向链表下一元素 
     } list; 

思路:复杂链表的复制,采用交错复制法达到O(n)时间复杂度,这里有完美解答:复杂链表复制

5,100万条数据的数据库查询速度优化问题,解决关键点是:根据主表元素特点,把主表拆分并新建副表,并且利用存储过程保证主副表的数据一致性。(不用写代码)

6,求正整数n所有可能的和式的组合(如;4=1+1+1+1、1+1+2、1+3、2+1+1、2+2)。点评:这里有一参考答案:http://blog.csdn.net/wumuzi520/article/details/8046350

看过后我也写了一个:

[cpp]  view plain copy
  1. /* 
  2. *   find the possible combination of a integer. 
  3. *   for example:4=1+1+1+1=1+2+1=1+3=2+2 
  4. */  
  5. #include<stdio.h>  
  6.   
  7. void find_combination_by_num(int sum,int num,int *pdata,int depth)  
  8. {  
  9.     if(sum<0||pdata==NULL) return;  
  10.     if(num==1)  
  11.     {  
  12.         pdata[depth]=sum;  
  13.         int i=0;  
  14.         for(;i<=depth;i++)  
  15.         {  
  16.             printf("%d ",pdata[i]);  
  17.         }  
  18.         printf("\n");  
  19.         return;  
  20.     }  
  21.     int i=0;  
  22.     if(depth==0)  
  23.     {  
  24.         i=1;//index form 1 when start.    
  25.     }else//index from the last i  
  26.     {  
  27.         i=pdata[depth-1];  
  28.     }  
  29.     for(;i<=sum/num;i++)  
  30.     {  
  31.         pdata[depth]=i;  
  32.         find_combination_by_num(sum-i,num-1,pdata,depth+1);  
  33.     }  
  34. }  
  35. void find_all_combinations(int sum,int *pdata)  
  36. {  
  37.     printf("all combinatins of %d:\n",sum);  
  38.     int i=2;  
  39.     for(;i<=sum;i++)  
  40.     {  
  41.         find_combination_by_num(sum,i,pdata,0);  
  42.     }  
  43. }  
  44. int main(int argc,char *argv[])  
  45. {  
  46.     int data[10]={0};  
  47.     find_all_combinations(10,data);  
  48.     return 0;  
  49. }  

7,求旋转数组的最小元素(把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1)。

思路:

除了正常情况,还要注意考虑三种特殊情况:

(1). 数组是没有发生过旋转的 {1,2,3,4,5,6}

(2). 全相等的数组 {1,1,1,1,1,1}

(3). 大部分都相等的数组 {1,0,1,1,1,1}

 二分查找的思路,最开始  如果数组没有旋转过,直接返回第一个元素,就是最小的元素; 如果旋转过,再按后续

首先获得 mid。 此时 ,若

  (1)  如果 ar[mid] > ar[left], 代表最小值肯定在后半区  left = mid + 1

  (2)  如果 ar[mid] < ar[left], 代表最小值肯定是在前半区到mid之间的(mid也有可能是最小值),  right = mid

  (3)  如果 ar[mid] == ar[left], 这种情况不好说了,需要进一步分析:

                 (1)若 ar[mid] == ar[right] , 最麻烦的情况,前中后都相等,只好排除首尾,继续找   left++   right--

                 (2)若 ar[mid] < ar[right], 代表最小值肯定在前半区, right = mid

                 (3)若 ar[mid] > ar[right], 代表最小值肯定在后半区, left = mid + 1

基于次我写了一个:

[cpp]  view plain copy
  1. /* 
  2. *   find min number in a sorted array after change. 
  3. *   for example:345612,the min is 1 
  4. *   the complexity of time shold be under O(n).  
  5. */  
  6.   
  7. #include<stdio.h>  
  8.   
  9. int find(const int data[],int length)  
  10. {  
  11.     if(data==NULL) return -1;  
  12.     int i=0;  
  13.     printf("the original data:\n");  
  14.     for(;i<length;i++)  
  15.     {  
  16.         printf("%d ",data[i]);  
  17.     }  
  18.     printf("\n");  
  19.     if(data[0]<data[length-1]) return data[0];  
  20.     int start=0,end=length-1,mid=length/2;  
  21.     while(start<end)  
  22.     {  
  23.         if(data[mid]>data[start])  
  24.         {  
  25.             start=mid+1;  
  26.         }else if(data[mid]<data[start])  
  27.         {  
  28.             end=mid;  
  29.         }else  
  30.         {  
  31.             if(data[mid]==data[end])  
  32.             {  
  33.                 start++;  
  34.                 end--;  
  35.             }else if(data[mid]>data[end])  
  36.             {  
  37.                 start=mid+1;  
  38.             }else if(data[mid]<data[end])  
  39.             {  
  40.                 end=mid;  
  41.             }  
  42.         }  
  43.         mid=(start+end)/2;  
  44.     }  
  45.     return data[end];  
  46. }  
  47.   
  48. int main(int argc,char *argv[])  
  49. {  
  50.     int data[10]={4,5,6,7,8,9,10,1,2,3};  
  51.     int res=find(data,10);  
  52.     printf("find min:%d\n",res);  
  53.     int data2[10]={1,1,1,1,1,1,1,1,1,1};  
  54.     res=find(data2,10);  
  55.     printf("find min:%d\n",res);  
  56.     int data3[10]={1,1,1,0,0,1,1,1,1,1};  
  57.     res=find(data3,10);  
  58.     printf("find min:%d\n",res);  
  59. }  

8,找出两个单链表里交叉的第一个元素

思路:求出两个链表长度L1和L2,假设L1>L2,长的链表先移动L2-L1次,然后两个链表分别比较相应元素直到相等或结束为止。

写代码时注意边界问题即可,十分简单代码略。

9,字符串移动(字符串为*号和26个字母的任意组合,把*号都移动到最左侧,把字母移到最右侧并保持相对顺序不变),要求时间和空间复杂度最小 
与第一题类似,不过比它简单,只要维护两个指针,一指向字符串第一个非*字符,一个指向其后的第一个*字符,然后二者交换并且都右移一位即可。

我写了一个:

[cpp]  view plain copy
  1. /* 
  2. *   move all the '*' in a string to the left 
  3. *   for example: "a*fc*3**fdj*3" the result is "*****afc3fdj3" 
  4. */  
  5.   
  6. #include<stdio.h>  
  7. void foo(char *str)  
  8. {  
  9.     printf("string before foo:%s\n",str);  
  10.     if(str==NULL) return ;  
  11.     int left=0,right=0;  
  12.     while(str[left]!='\0'&&str[right]!='\0')  
  13.     {  
  14.         while(str[left]!='\0'&&str[left]=='*') left++;  
  15.         if(str[left]=='\0'break;  
  16.         right=left+1;  
  17.         while(str[right]!='\0'&&str[right]!='*') right++;  
  18.         if(str[right]=='\0'break;  
  19.         char temp=str[left];  
  20.         str[left]=str[right];  
  21.         str[right]=temp;      
  22.         left++;  
  23.         right++;  
  24.     }  
  25.     printf("string after foo:%s\n",str);  
  26. }  
  27. int main(int argc,char *argv[])  
  28. {  
  29.     char str[20]="***ad*h**f****";  
  30.     foo(str);  
  31.     char str1[20]="a*d**h***f";  
  32.     foo(str1);  
  33.     char str2[20]="***a*d*h**fhg";  
  34.     foo(str2);  
  35.     char str3[20]="a*d*h**f**g***";  
  36.     foo(str3);  
  37.       
  38.     return 0;  
  39. }  

10,时间复杂度为O(1),怎么找出一个栈里的最大元素   

思路:比较简单,新建一个辅助栈即可,里面存放当前栈中最大元素,当数据栈中压入一个数时如果这个数比辅助栈栈顶元素大则同步压入辅助栈,否则压入辅助栈栈顶元素,弹出时辅助栈弹出一个元素即可,那么数据栈中当前最大元素就是辅助栈中的栈顶元素。

代码简单略。

11,线程、进程区别

答案见3.百度笔试题第二小题。

12,static在C和C++里各代表什么含义 
对于局部变量和全局变量(函数)而言static的作用C和C++一样。

(1)局部变量

在C/C++中, 局部变量按照存储形式可分为三种auto, static, register

与auto类型(普通)局部变量相比, static局部变量有三点不同

1. 存储空间分配不同

auto类型分配在栈上, 属于动态存储类别, 占动态存储区空间, 函数调用结束后自动释放, 而static分配在静态存储区, 在程序整个运行期间都不释放. 两者之间的作用域相同, 但生存期不同.

2. static局部变量在所处模块在初次运行时进行初始化工作, 且只操作一次

3. 对于局部静态变量, 如果不赋初值, 编译期会自动赋初值0或空字符, 而auto类型的初值是不确定的. (对于C++中的class对象例外, class的对象实例如果不初始化, 则会自动调用默认构造函数,不管是否是static类型)

特点: static局部变量的”记忆性”与生存期的”全局性”

所谓”记忆性”是指在两次函数调用时, 在第二次调用进入时, 能保持第一次调用退出时的值.

(2)外部(全局)静态变量/函数

在C中 static有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。但为了限制全局变量/函数的作用域, 函数或变量前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函 数)。注意此时, 对于外部(全局)变量, 不论是否有static限制, 它的存储区域都是在静态存储区,
生存期都是全局的. 此时的static只是起作用域限制作用, 限定作用域在本模块(文件)内部.使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名.

(3)C++中静态数据成员/成员函数

C+ +重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数. 这是与普通成员函数的最大区别,
也是其应用所在, 比如在对某一个类的对象进行计数时, 计数生成多少个类的实例,
就可以用到静态数据成员. 在这里面, static既不是限定作用域的, 也不是扩展生存期的作用, 而是指示变量/函数在此类中的唯一性. 这也是”属于一个类而不是属于此类的任何特定对象的变量和函数”的含义. 因为它是对整个类来说是唯一的,
因此不可能属于某一个实例对象的. (针对静态数据成员而言, 成员函数不管是否是static, 在内存中只有一个副本, 普通成员函数调用时, 需要传入this指针, static成员函数调用时, 没有this指针. )

13,const 在C/C++里什么意思 
在C中,const可以用来修饰常量,函数参数和函数返回值,C++const除了C中用法外还可以用来修饰常成员函数。

具体可以看着里:http://blog.csdn.net/kevinguozuoyong/article/details/5904627

14,常用linux命令

hostname:显示主机名
uname:显示系统信息
cut:用来移除文件的部分内容。
diff:用来找出两个文件的不同之处。
du: 用来显示磁盘的剩余空间的大小。
file:用来显示文件的类型。
find:用来在目录中搜索文件,并执行指定的操作。
head:只查看文件的头
source:使得刚修改的文件生效
read:从标准设备读入
cat:可以显示文件的内容(经常和more搭配使用),或将多个文件合并成一个文件。
chgrp:用来改变文件或目录所属的用户组,命令的参数以空格分开的要改变属组的文件列表,文件名支持通配符,如果用户不是该文件的所有者,则不能改变该文件的所属组。
chmod:用于改变文件或目录的访问权限,该命令有两种用法:一种是使用图形化的方法,另一种是数字设置法。
chown:用来将指定用户或组为特定的所有者。用户可以设置为用户名或用户ID,组可以是组名或组ID。特定的文件是以空格分开的可以改变权限的文件列表,文件名支持通配符。
clear:用来清除终端屏幕。

cd directory 进入指定的目录 
cd .. 进入上一级目录 
cd /directory 进入目录 
cd 进入用户自己的目录 
cp file_from file_to 拷贝文件 
ln [-s] source linkname 为一个文件建立连结 
ls [directory] 查看指定目录下的文件 
ls -l [directory] 查看指定目录下文件的详细 
ls -a [directory] 查看指定目录下的所有文件 
mkdir new_directory 建一个新目录 
more file 查看一个文本文件的内容 
rm file 删除一个文件 
rm -r directory 删除一个目录 
rmdir directory 删除一个目录 
find . -name "file" 从当前目录开始查找指定的文件 
adduser 创建新用户 
alias 设置别名或替代名 
bg fg 使挂起的进程继续运行 
ps ax 查询当前进程 
mount 连接文件系统 
more less 浏览文件内容 
chown chgrp 改变文件的拥有者 
chmod 改变文件属性 
halt 关闭系统 
man 显示手册页 
passwd 改变用户口令 
grep 查找字符串 
find 查找文件 
dd 复制磁盘或文件系统 
kill 杀掉一个进程 
killall 杀掉进程

15,解释Select/Poll模型

I/O复用模型(Select/Poll)

I/O复用模型会用到select或者poll函数,这两个函数也会使进程阻塞,但是和阻塞I/O所不同的的,这两个函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。

详细信息请看:http://hi.baidu.com/nivrrex/item/54f782cfe821ef09c710b2a6

6,网易有道二面

判断一个数字序列是BST【二叉排序树(Binary Search Tree:BST)】后序遍历的结果,现场写代码。

思路:采用递归判断,一颗二叉树包含左子树,右子树以及根结点,根据二叉排序树的特新,左子树的所有结点均小于根结点,而右子树的所有结点均大于根结点,利用这个特新可以用来递归判断是否是二叉树的序列。对于后序遍历,最后一个数是根结点,其中要点是找到左子树与右子树的分界点,由二叉树的性质可知第一个大于根节点的数即是右子树中的节点,由此可以区分左子树与右子树。

我写了一个:

[cpp]  view plain copy
  1. /* 
  2. *   judge an array whether is a post order of a binary search tree. 
  3. *   for example:4 8 7 11 14 12 9 is yes,4 11 7 8 14 12 9 is no! 
  4. */  
  5.   
  6. #include<stdio.h>  
  7.   
  8. bool judge_post_of_BST(const int data[],int start,int end);  
  9.   
  10. void judge(const int data[],int length)  
  11. {  
  12.     if(data==NULL) return;  
  13.     printf("the array is:\n");  
  14.     int i=0;  
  15.     while(i<length) printf("%d ",data[i++]);  
  16.     printf("\n");  
  17.     bool res=judge_post_of_BST(data,0,length-1);  
  18.     if(res) printf("the array is a post order of BST.\n");  
  19.     else printf("the array is not a post order of BST!\n");  
  20. }  
  21. bool judge_post_of_BST(const int data[],int start,int end)  
  22. {  
  23.     if(start>=end) return true;  
  24.     int index_right=-1,i=0;  
  25.     for(i=start;i<=end;i++)  
  26.     {  
  27.         if(index_right!=-1&&data[i]<data[end]) return false;  
  28.         if(index_right==-1&&data[i]>data[end]) index_right=i;  
  29.     }  
  30.     bool l=false,r=false;  
  31.     l=judge_post_of_BST(data,start,index_right-1);  
  32.     r=judge_post_of_BST(data,index_right,end-1);  
  33.     return l&&r;  
  34. }  
  35.   
  36. int main(int argc,char *argv[])  
  37. {  
  38.     int data[7]={4,8,7,11,14,12,9};  
  39.     judge(data,7);  
  40.     int data2[7]={4,11,7,8,14,12,9};  
  41.     judge(data2,7);  
  42.     return 0;  
  43. }  

7,8月30日,网易有道面试题

var tt = 'aa';
function test()
{
  alert(tt);
  var tt = 'dd';
  alert(tt);
}
test();  
什么意思?要求干嘛?是写出打印结果还是改错?

8,8月31日,百度面试题:不使用随机数的洗牌算法

这里有一堆大牛的讨论:http://bbs.csdn.net/topics/390195922

9,9月6日,阿里笔试题:平面上有很多点,点与点之间有可能有连线,求这个图里环的数目。

可以看看这里:http://blog.csdn.net/chinaczy/article/details/5730601

10,9月7日,一道华为上机题:

题目描述: 选秀节目打分,分为专家评委和大众评委,score[] 数组里面存储每个评委打的分数,judge_type[] 里存储与 score[] 数组对应的评委类别,judge_type == 1,表示专家评委,judge_type == 2,表示大众评委,n表示评委总数。打分规则如下:专家评委和大众评委的分数先分别取一个平均分(平均分取整),然后,总分 = 专家评委平均分 * 0.6 + 大众评委 * 0.4,总分取整。如果没有大众评委,则 总分 = 专家评委平均分,总分取整。函数最终返回选手得分。
函数接口 int cal_score(int score[], int judge_type[], int n)  
 上机题目需要将函数验证,但是题目中默认专家评委的个数不能为零,但是如何将这种专家数目为0的情形排除出去。

思路:比较简单,只要注意只有专家评委和只有大众评委的情况,代码略。

11,9月8日,腾讯面试题:

假设两个字符串中所含有的字符和个数都相同我们就叫这两个字符串匹配,
 比如:abcda和adabc,由于出现的字符个数都是相同,只是顺序不同,
 所以这两个字符串是匹配的。要求高效!
又是跟上述第3题中简单题一的兄弟节点类似的一道题,我想,你们能想到的,这篇blog里:http://blog.csdn.net/v_JULY_v/article/details/6347454都已经有了。

12,阿里云,搜索引擎中5亿个url怎么高效存储;

思路:B+数,分布式存储

13,一道C++笔试题,求矩形交集的面积:

在一个平面坐标系上,有两个矩形,它们的边分别平行于X和Y轴。
其中,矩形A已知, ax1(左边), ax2(右边), ay1(top的纵坐标), ay2(bottom纵坐标). 矩形B,类似,就是 bx1, bx2, by1, by2。这些值都是整数就OK了。
要求是,如果矩形没有交集,返回-1, 有交集,返回交集的面积。
int area(rect const& a, rect const& b)
{
  ...
}

点评
healer_kx:
补齐代码,最好是简洁的,别用库。你可以写你的辅助函数,宏定义,代码风格也很重要。
ri_aje:

[cpp]  view plain copy
  1. struct rect    
  2. {    
  3.  // axis alignment assumed    
  4.  // bottom left is (x[0],y[0]), top right is (x[1],y[1])    
  5.  double x [2];    
  6.  double y [2];    
  7. };    
  8.     
  9. template <typename T> T const& min (T const& x, T const& y) { return x<y ? x : y; }    
  10. template <typename T> T const& max (T const& x, T const& y) { return x>y ? x : y; }    
  11.     
  12. // return type changed to handle non-integer rects    
  13. double area (rect const& a, rect const& b)    
  14. {    
  15.  // perfectly adjacent rects are considered having an intersection of 0 area    
  16.  double const dx = min(a.x[1],b.x[1]) - max(a.x[0],b.x[0]);    
  17.  double const dy = min(a.y[1],b.y[1]) - max(a.y[0],b.y[0]);    
  18.  return dx>=0&&dy>=0 ? dx*dy : -1;    
  19. }    
下面是一个简短的证明。
对于平行于坐标轴的矩形 r,假设其左下角点坐标为 (rx0,ry0),右上角点坐标为 (rx1,ry1),那么由 r 定义的无限有界点集为:{(x,y)|x in [rx0,rx1] && y in [ry0,ry1]}。
根据交集的定义,则任意二维点 (x,y) 在矩形 a,b 的交集内等价于
{(x,y)|(x,y) in a 并且 (x,y) in b} <==>
{(x,y)|x in [ax0,ax1] && x in [bx0,bx1] 并且 y in [ay0,ay1] && y in [by0,by1]} <==>
{(x,y)|x in [max(ax0,bx0),min(ax1,bx1)] 并且 y in [max(ay0,by0),min(ay1,by1)]}
因此,交集矩形的边长分别为 min(ax1,bx1)-max(ax0,bx0) 和 min(ay1,by1)-max(ay0,by0)。注意当交集为空时(a,b 不相交),则经此法计算出来的交集边长为负值,此事实可用于验证 a,b 的相交性。
鉴于笛卡尔积各个维度上的不相关性,此方法可扩展到任意有限维线性空间,比如,三维空间中平行于坐标轴的长方体的交集体积可以用类似的方法计算。

来源:http://topic.csdn.net/u/20120913/18/bc669d60-b70a-4008-be65-7c342789b925.html

14,2012年创新工场校园招聘最后一道笔试题:工场很忙

创新工场每年会组织同学与项目的双选会,假设现在有M个项目,编号从1到M,另有N名同学,编号从1到N,每名同学能选择最多三个、最少一个感兴趣的项目。选定之后,HR会安排项目负责人和相应感兴趣的同学一对一面谈,每次面谈持续半小时。由于大家平时都很忙,所以咱们要尽量节约时间,请你按照以下的条件设计算法,帮助HR安排面试。
1)同学很忙。项目负责人一次只能与一名同学面谈,而同学会在自己第一个面试开始时达到工场,最后一个面试结束后离开工场,如果参加一个项目组的面试后不能立即参加下一个项目组的面试,就必须在工场等待。所以请尽可能让同学的面试集中在某一时间段,减少同学在工场等待的时间。
2)项目负责人很忙。众所周知,创业团队的负责人会有很多事情要做,所以他们希望能够将自己参与的面试集中在某一段时间内,请在保证1)的情况下,使得项目负责人等待的时间最少。
3)HR很忙。从第一轮面试开始以后,所有HR都必须等到最后一轮面试结束,所以需要在保证1)和2)的同时,也能尽快解放掉所有的HR,即让第一轮面试到最后一轮面试之间持续的时间最短。

输入(以文件方式输入,文件名为iw,例如iw.in):
    第1行...第n行:同学的编号 项目的编号
    样例(数据间用空格隔开,两个0表示输入结束):           
1
1 2
3
1
1
2
0             
    表示M=3,N=3,编号为1的同学选择了项目1,2和3,编号为2的同学选择了项目1,编号为3的同学选了项目1和2

输出(以文件方式输出,文件名为iw,例如iw.out):
    第1行:编号为1的项目依次面试新同学的编号序列
    第2行:编号为2的项目依次面试新同学的编号序列
    ...
    第n行:编号为n的项目依次面试新同学的编号序列
    样例(数据间用空格隔开,0表示没有面试):
1 2
0
1
    表示编号为1的项目在第一轮面试编号为1的同学,第二轮面试编号为3的同学,第三轮面试编号为2的同学
    编号为2的项目在第一轮面试编号为3的同学,第二轮面试编号为1的同学,第三轮不用面试
    编号为3的项目在第一轮和第二轮都不用面试,第三轮面试编号为1的同学

链接:http://t.qq.com/p/t/108332110988802

我的思路:

按顺序分别安排每一个同学,安排一个同学面试的算法如下:

设项目组为个数为M,同学个数为N,同学编号为i,每一个项目设置一个二维矩阵matrix[M][3*N],表示每个项目安排同学面试的序列,矩阵初始为空,其中数字代表学生编号,每个项目序列数组初始大小为N*3,设置一个大小为[N][M]的数组data,保存每个同学选择面试的项目序列。

1)i取值0...N-1,对于编号为i的同学,从1...3*M取值k遍历

2)matrix[x][y],x取值0...M-1,y取值k,依次遍历matrix[x][y],记录下其中x值为data[k]非0值的元素且matrix[x][y]为空的位置对应项目,没找到则k++

3)k>3*M则动态扩展matrix对应序列的大小。

3)在这些项目中选择面试序列数组中剩下空位最多的一个s,将其分配给i同学面试,matrix[s][k]=0,同时把i同学对应项目的值设为0表示已安排:data[i][s]=0,直到data[i]中数组值全为0即该同学所有项目面试都安排了为止,再i++回到1)。

我写了一个(时间和空间复杂度较高,假如有更好的解法欢迎指正):

[cpp]  view plain copy
  1. #include<stdio.h>  
  2. #include<iostream>  
  3. #include<stdlib.h>  
  4. #include<string.h>  
  5. using namespace std;  
  6.   
  7.   
  8. typedef struct _Project  
  9. {  
  10.     int no;//the number of project  
  11.     int *stuArray;//the array of the student arrangment  
  12.     int size;//the size of the array  
  13.     //int size_left;//the left size of the array  
  14. }Project,*pProject;   
  15. typedef struct _Student  
  16. {  
  17.     int no;//the number of the student  
  18.     int *proArray;//the array of the projects that he chose  
  19.     int size;//  
  20.     int size_left;//  
  21. }Student,*pStudent;  
  22.   
  23. class Match  
  24. {  
  25. public:  
  26.     Match(const char *filename,int _M,int _N);  
  27. private:  
  28.     void Init();  
  29.     void LoadDataFromFile(FILE* fp);  
  30.     void StartMatch();  
  31.     void StoreResult(FILE *fp);  
  32.     int M,N;//the number of projects and students  
  33.     pProject mpProjects;//the total projects   
  34.     pStudent mpStudents;//the total students  
  35. };  
  36. Match::Match(const char *filename,int _M,int _N):M(_M),N(_N)  
  37. {  
  38.     Init();  
  39.     if(filename==NULL) return;  
  40.     FILE *fp;  
  41.     if((fp=fopen(filename,"r"))==NULL)  
  42.     {  
  43.         cout<<"open file failed!"<<endl;  
  44.         return;  
  45.     }  
  46.     LoadDataFromFile(fp);  
  47.     fclose(fp);  
  48.     StartMatch();  
  49.     if((fp=fopen("out.txt","wt"))==NULL)  
  50.     {  
  51.         cout<<"open file failed!"<<endl;  
  52.         return;  
  53.     }  
  54.     StoreResult(fp);  
  55.     fclose(fp);  
  56. }  
  57. void Match::Init()  
  58. {  
  59.     mpProjects=new Project[M];  
  60.     int i,j;  
  61.     for(i=0;i<M;i++)  
  62.     {  
  63.         mpProjects[i].no=i+1;  
  64.         mpProjects[i].stuArray=new int[3*N];  
  65.         mpProjects[i].size=0;  
  66.         //mpProjects[i].size_left=0;      
  67.         for(j=0;j<3*N;j++)  
  68.         {  
  69.             mpProjects[i].stuArray[j]=-1;//initial  
  70.         }  
  71.     }  
  72.     mpStudents=new Student[N];  
  73.     for(i=0;i<N;i++)  
  74.     {  
  75.         mpStudents[i].no=i+1;  
  76.         mpStudents[i].proArray=new int[M];  
  77.         mpStudents[i].size=0;  
  78.         mpStudents[i].size_left=0;  
  79.         for(j=0;j<M;j++)  
  80.         {  
  81.             mpStudents[i].proArray[j]=-1;//  
  82.         }  
  83.     }  
  84. }  
  85. void Match::LoadDataFromFile(FILE *fp)  
  86. {  
  87.       
  88.     char ch;  
  89.     int p=-1,s=-1;  
  90.     bool change=false;  
  91.     printf("input data:\n");  
  92.     while((ch=fgetc(fp))!=EOF)  
  93.     {  
  94.         if(ch=='0'break;  
  95.         if(ch=='\n')//set data   
  96.         {  
  97.             int k=0;  
  98.             while(mpStudents[s-1].proArray[k]!=-1) k++;  
  99.             mpStudents[s-1].proArray[k]=p-1;  
  100.             mpStudents[s-1].size++;  
  101.             mpStudents[s-1].size_left++;      
  102.             printf("%d,%d\n",s,p);  
  103.             s=-1,p=-1;  
  104.             change=false;     
  105.         }  
  106.         else  
  107.         {   if(ch>='0'&&ch<='9')  
  108.             {  
  109.                 if(!change)//input the first number whitch represents student  
  110.                 {  
  111.                     if(s==-1) s=ch-'0';  
  112.                     else s=s*10+ch-'0';  
  113.                 }else//input the second number whitch represent project  
  114.                 {  
  115.                     if(p==-1) p=ch-'0';  
  116.                     else p=p*10+ch-'0';   
  117.                 }  
  118.             }else if(ch==' ')  
  119.             {  
  120.                 change=true;  
  121.             }  
  122.         }  
  123.     }  
  124. }  
  125. void Match::StartMatch()  
  126. {  
  127.     int i;  
  128.     for(i=0;i<N;i++)//through N students  
  129.     {  
  130.         int order=0;  
  131.         int match=0;  
  132.         const int S=M;  
  133.         int chose[S];  
  134.         memset(chose,0,sizeof(int)*S);  
  135.         while(mpStudents[i].size_left>0)  
  136.         {  
  137.             int j;  
  138.             match=0;  
  139.             for(j=0;j<mpStudents[i].size;j++)  
  140.             {  
  141.                 if(mpStudents[i].proArray[j]==-2) continue;//already arranged  
  142.                 int pro=mpStudents[i].proArray[j];  
  143.                 if(mpProjects[pro].stuArray[order]==-1)  
  144.                 {  
  145.                     chose[match++]=pro;  
  146.                 }  
  147.             }  
  148.             if(match>0)//find match projects  
  149.             {  
  150.                 if(match==1)//only one project match  
  151.                 {  
  152.                     int p=chose[0];  
  153.                     mpProjects[p].stuArray[order]=i;  
  154.                     mpProjects[p].size++;  
  155.                     int k=0;  
  156.                     while(mpStudents[i].proArray[k]!=p) k++;  
  157.                     mpStudents[i].proArray[k]=-2;//arrange this project,set 0  
  158.                     mpStudents[i].size_left--;  
  159.                 }else//more than one matched,chose the one whitch left_size is max  
  160.                 {  
  161.                     int i_min=0;  
  162.                     int k,min=0;      
  163.                     for(k=0;k<match;k++)  
  164.                     {  
  165.                         int c=chose[k];  
  166.                         if(mpProjects[c].size<min) i_min=k;    
  167.                     }  
  168.                     int p=chose[i_min];  
  169.                     mpProjects[p].stuArray[order]=i;  
  170.                     mpProjects[p].size++;  
  171.                     k=0;  
  172.                     while(mpStudents[i].proArray[k]!=p) k++;  
  173.                     mpStudents[i].proArray[k]=-2;//arrange this project,set 0  
  174.                     mpStudents[i].size_left--;  
  175.                 }  
  176.             }  
  177.             order++;  
  178.         }  
  179.     }  
  180. }  
  181. void Match::StoreResult(FILE *fp)  
  182. {  
  183.     printf("result :\n");  
  184.     for(int i=0;i<M;i++)  
  185.     {  
  186.         printf("project %d:,",i+1);  
  187.         int j;  
  188.         char *buf=new char[20];  
  189.         memset(buf,'\0',20);  
  190.         char *str=new char[5];  
  191.         memset(str,'\0',5);  
  192.         for(j=0;j<mpProjects[i].size;j++)  
  193.         {  
  194.             printf("%d ",mpProjects[i].stuArray[j]+1);  
  195.             sprintf(str,"%d ",mpProjects[i].stuArray[j]+1);  
  196.             strcat(buf,str);  
  197.         }  
  198.         strcat(buf,"\n");  
  199.         fputs(buf,fp);    
  200.         printf("\n");  
  201.     }  
  202.     printf("write data to file.\n");  
  203. }  
  204. int main(int argc,char *argv[])  
  205. {  
  206.     Match m("data.txt",4,4);  
  207.     return 0;  
  208. }  

15,4**9 的笔试题,比较简单:

1,求链表的倒数第二个节点

思路:两个指针,一前一后,不多说。

2,有一个整数数组,求数组中第二大的数

思路:维护两个数,每次把数组中的数与这两个数比较,比它们中小的大则相互替换,一次类推。

16,阿里巴巴二道题

1,对于给定的整数集合S,求出最大的d,使得a+b+c=d。a,b,c,d互不相同,且都属于S。集合的元素个数小于等于2000个,元素的取值范围在[-2^28,2^28 - 1],假定可用内存空间为100MB,硬盘使用空间无限大,试分析时间和空间复杂度,找出最快的解决方法。

点评:
@绿色夹克衫:两两相加转为多项式乘法,比如(1 2 4 6) + (2 3 4 5) => (x + x^2 + x^4 + x^6)*(x^2 + x^3 + x^4 + x^5) 。更多思路请见这

http://www.51nod.com/answer/index.html#!answerId=569

2,原题大致描述有一大批数据,百万级别的。数据项内容是:用户ID、科目ABC各自的成绩。其中用户ID为0~1000万之间,且是连续的,可以唯一标识一条记录。科目ABC成绩均在0~100之间。有两块磁盘,空间大小均为512M,内存空间64M。
1) 为实现快速查询某用户ID对应的各科成绩,问磁盘文件及内存该如何组织;
2) 改变题目条件,ID为0~10亿之间,且不连续。问磁盘文件及内存该如何组织;

3) 在问题2的基础上,增加一个需求。在查询各科成绩的同时,获取该用户的排名,问磁盘文件及内存该如何组织。

思路:1),1000W个数据记录,每个记录采用6个字节存储,大约需要60M,因此可以全部放入内存,又因为ID连续,因此在内存中可以采用数组进行存取数据。

2),采用hash方法,将大量记录hash到两块磁盘上,查询时直接求出hash值找到对应的磁盘记录进行查询。

3),

3,代码实现计算字符串的相似度。

点评:和计算两字符串的最长公共子序列相似。
设Ai为字符串A(a1a2a3 … am)的前i个字符(即为a1,a2,a3 …ai
设Bj为字符串B(b1b2b3 … bn)的前j个字符(即为b1,b2,b3 …bj)
设 L(i , j)为使两个字符串Ai和Bj相等的最小操作次数。
当ai等于bj时 显然L(i, j)=L(i-1, j-1)
当ai不等于bj时
  若将它们修改为相等,则对两个字符串至少还要操作L(i-1, j-1)次
  若删除ai或在Bj后添加ai,则对两个字符串至少还要操作L(i-1, j)次
  若删除bj或在Ai后添加bj,则对两个字符串至少还要操作L(i, j-1)次
  此时L(i, j)=min( L(i-1, j-1), L(i-1, j), L(i, j-1) )  + 1
显然,L(i, 0)=i,L(0, j)=j, 再利用上述的递推公式,可以直接计算出L(i, j)值。具体代码请见这:

http://blog.csdn.net/flyinghearts/article/details/5605996

17,9月14日,小米笔试

给一个浮点数序列,取最大乘积子序列的值,例如 -2.5,4,0,3,0.5,8,-1,则取出的最大乘积子序列为3,0.5,8。

点评:
解法一、
     或许,读者初看此题,自然会想到最大乘积子序列问题类似于最大子数组和问题:http://blog.csdn.net/v_JULY_v/article/details/6444021,然实则具体处理起来诸多不同,为什么呢,因为乘积子序列中有正有负也还可能有0。
    既如此,我们可以把问题简化成这样:数组中找一个子序列,使得它的乘积最大;同时找一个子序列,使得它的乘积最小(负数的情况)。因为虽然我们只要一个最大积,但由于负数的存在,我们同时找这两个乘积做起来反而方便。也就是说,不但记录最大乘积,也要记录最小乘积。So
我们让maxCurrent表示当前最大乘积的candidate,
minCurrent反之,表示当前最小乘积的candidate。
(用candidate这个词是因为只是可能成为新一轮的最大/最小乘积),
而maxProduct则记录到目前为止所有最大乘积candidates的最大值。

    由于空集的乘积定义为1,在搜索数组前,maxCurrent,minCurrent,maxProduct都赋为1。
假设在任何时刻你已经有了maxCurrent和minCurrent这两个最大/最小乘积的candidates,新读入数组的元素x(i)后,新的最大乘积candidate只可能是maxCurrent或者minCurrent与x(i)的乘积中的较大者,如果x(i)<0导致maxCurrent<minCurrent,需要交换这两个candidates的值。
    当任何时候maxCurrent<1,由于1(空集)是比maxCurrent更好的candidate,所以更新maxCurrent为1,类似的可以更新minCurrent。任何时候maxCurrent如果比最好的maxProduct大,更新maxProduct。
    具体代码如下:

  1. template <typename Comparable>  
  2. Comparable maxprod( const vector<Comparable>&v)  
  3. {  
  4.     int i;  
  5.     Comparable maxProduct = 1;  
  6.     Comparable minProduct = 1;  
  7.     Comparable maxCurrent = 1;  
  8.     Comparable minCurrent = 1;  
  9.     //Comparable t;  
  10.   
  11.     for( i=0; i< v.size() ;i++)  
  12.     {  
  13.         maxCurrent *= v[i];  
  14.         minCurrent *= v[i];  
  15.         if(maxCurrent > maxProduct)   
  16.             maxProduct = maxCurrent;  
  17.         if(minCurrent > maxProduct)  
  18.             maxProduct = minCurrent;  
  19.         if(maxCurrent < minProduct)  
  20.             minProduct = maxCurrent;  
  21.         if(minCurrent < minProduct)  
  22.             minProduct = minCurrent;  
  23.         if(minCurrent > maxCurrent)  
  24.             swap(maxCurrent,minCurrent);  
  25.         if(maxCurrent<1)  
  26.             maxCurrent = 1;  
  27.         //if(minCurrent>1)  
  28.         //    minCurrent =1;  
  29.     }  
  30.     return maxProduct;   
  31. }  
解法二、
    本题除了上述类似最大子数组和的解法,也可以直接用动态规划求解( 其实,上述的解法一本质上也是动态规划,只是解题所表现出来的具体形式与接下来的解法二不同罢了。这个不同就在于下面的解法二会写出动态规划问题中经典常见的状态转移方程,而解法一是直接求解 )。具体解法如下:
    假设数组为a[],直接利用动归来求解,考虑到可能存在负数的情况,我们用Max[i]来表示以a[i]结尾的最大连续子序列的乘积值,用Min[i]表示以a[i]结尾的最小的连续子序列的乘积值,那么状态转移方程为:
       Max[i]=max{a[i], Max[i-1]*a[i], Min[i-1]*a[i]};
       Min[i]=min{a[i], Max[i-1]*a[i], Min[i-1]*a[i]};
    初始状态为Max[1]=Min[1]=a[1]。代码如下:
  1. /* 
  2.  给定一个整数数组,有正有负数,0,正数组成,数组下标从1算起 
  3.  求最大连续子序列乘积,并输出这个序列,如果最大子序列乘积为负数,那么就输出-1 
  4.  用Max[i]表示以a[i]结尾乘积最大的连续子序列 
  5.  用Min[i]表示以a[i]结尾乘积最小的连续子序列  因为有复数,所以保存这个是必须的 
  6. */  
  7. void longest_multiple(int *a,int n){  
  8.  int *Min=new int[n+1]();  
  9.  int *Max=new int[n+1]();  
  10.  int *p=new int[n+1]();  
  11.  //初始化  
  12.  for(int i=0;i<=n;i++){  
  13.   p[i]=-1;  
  14.  }  
  15.  Min[1]=a[1];  
  16.  Max[1]=a[1];  
  17.  int max_val=Max[1];  
  18.  for(int i=2;i<=n;i++){  
  19.   Max[i]=max(Max[i-1]*a[i],Min[i-1]*a[i],a[i]);  
  20.   Min[i]=min(Max[i-1]*a[i],Min[i-1]*a[i],a[i]);  
  21.   if(max_val<Max[i])  
  22.    max_val=Max[i];  
  23.  }  
  24.  if(max_val<0)  
  25.   printf("%d",-1);  
  26.  else  
  27.   printf("%d",max_val);  
  28. //内存释放  
  29.  delete [] Max;  
  30.  delete [] Min;  
  31. }  
变种
    此外,此题还有另外的一个变种形式,即给
定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合中乘积最大的一组,并写出算法的时间复杂度。
  我们可以把所有可能的(N-1)个数的组合找出来,分别计算它们的乘积,并比较大小。由于总共有N个(N-1)个数的组合,总的时间复杂度为O(N2),显然这不是最好的解法。
  OK,以下解答来自编程之美
解法1

解法2
  此外,还可以通过分析,进一步减少解答问题的计算量。假设N个整数的乘积为P,针对P的正负性进行如下分析(其中,AN-1表示N-1个数的组合,PN-1表示N-1个数的组合的乘积)。
   1.P为0
          那么,数组中至少包含有一个0。假设除去一个0之外,其他N-1个数的乘积为Q,根据Q的正负性进行讨论:
Q为0
说明数组中至少有两个0,那么N-1个数的乘积只能为0,返回0;
Q为正数
返回Q,因为如果以0替换此时AN-1中的任一个数,所得到的PN-1为0,必然小于Q
Q为负数
如果以0替换此时AN-1中的任一个数,所得到的PN-1为0,大于Q,乘积最大值为0。

     2.    P为负数

根据“负负得正”的乘法性质,自然想到从N个整数中去掉一个负数,使得PN-1为一个正数。而要使这个正数最大,这个被去掉的负数的绝对值必须是数组中最小的。我们只需要扫描一遍数组,把绝对值最小的负数给去掉就可以了。

      3.    P为正数

类似地,如果数组中存在正数值,那么应该去掉最小的正数值,否则去掉绝对值最大的负数值。
    上面的解法采用了直接求N个整数的乘积P,进而判断P的正负性的办法,但是直接求乘积在编译环境下往往会有溢出的危险(这也就是本题要求不使用除法的潜在用意),事实上可做一个小的转变,不需要直接求乘积,而是求出数组中正数(+)、负数(-)和0的个数,从而判断P的正负性,其余部分与以上面的解法相同。
    在时间复杂度方面,由于只需要遍历数组一次,在遍历数组的同时就可得到数组中正数(+)、负数(-)和0的个数,以及数组中绝对值最小的正数和负数,时间复杂度为O(N)。

18,9月15日,中兴面试

小端系统

[cpp]  view plain copy
  1. union{    
  2.         int i;    
  3.         unsigned char ch[2];    
  4. }Student;    
  5.     
  6.     
  7. int main()    
  8. {    
  9.         Student  student;    
  10.         student.i=0x1420;    
  11.         printf("%d  %d",student.ch[0],student.ch[1]);    
  12.     return 0;    
  13. }    
输出结果为?

答案:32,20

19,一道有趣的Facebook面试题:

给一个二叉树,每个节点都是正或负整数,如何找到一个子树,它所有节点的和最大? 
点评:
答案:后序遍历,每一个节点保存左右子树的和加上自己的值。额外一个空间存放最大值。
补充:同学们,如果你面试的是软件工程师的职位,一般面试官会要求你在短时间内写出一个比较整洁的,最好是高效的,没有什么bug的程序。所以,光有算法不够,还得多实践。
写完后序遍历,面试官可能接着与你讨论,a). 如果要求找出只含正数的最大子树,程序该如何修改来实现?b). 假设我们将子树定义为它和它的部分后代,那该如何解决?c). 对于b,加上正数的限制,方案又该如何?总之,一道看似简单的面试题,可能能变换成各种花样。
比如,面试管可能还会再提两个要求:第一,不能用全局变量;第一,有个参数控制是否要只含正数的子树。其它的,随意,当然,编程风格也很重要。

20,谷歌面试题:

有几百亿的整数,分布的存储到几百台通过网络连接的计算机上,你能否开发出一个算法和系统,找出这几百亿数据的中值?就是在一组排序好的数据中居于中间的数。显然,一台机器是装不下所有的数据。也尽量少用网络带宽。

思路:

m1: 

将0-2^32划分为若干个桶,每个电脑放一个桶,每个桶内有个计数器,记录有多少数放在桶内

从第一个桶的计数器开始加,一直加到大于n/2

所以中位数肯定在这个桶内


m2:

http://matpalm.com/median/distributing.html

http://matpalm.com/median/erlang_multi.html


利用快排的思想,但是只计数不交换位置,节省移动操作。

in the multi process implementation splits the list of numbers to consider into a sub lists
each sub list can be handled by a seperate erlang process, potentially across different machines
(these lists don't have to be the same size)

single [1,2,3,4,5,6,7,8,9]
multi  [[1,2,3,4],[5,6],[7,8,9]]

recall there a number of operations required in distributed case
includes things like determining total number of elements, determining minimum value, etc
each of these operations can be done against each sub list individually with the results aggregated

eg to determine total number of elements

single -> length( [1,2,3,4,5,6,7,8,9] ) = 9
multi  -> sum ( length([1,2,3,4]), length([5,6]), length([7,8,9]) ) = sum([4,2,3]) = 9

eg to determine minimum value

single -> min( [1,2,3,4,5,6,7,8,9] ) = 1
multi  -> min( min([1,2,3,4]), min([5,6]), min([7,8,9]) ) = min([1,5,7]) = 1

other changes required

rotation

in the single list case we pick the pivot as the first value.
in the multi list case we pick the pivot as the first value of the first list.
recall in the algorithm that rotation is sometimes required.
this is to ensure all potential values for a pivot are explored.
so in the multi list case the rotation needs to operate at two levels; rotate the first list and then rotate the list of lists

before [[1,2,3],[4,5,6],[7,8,9]]
after  [[4,5,6],[7,8,9],[2,3,1]]

21,小米,南京站笔试(原第20题):

一个数组里,数都是两两出现的,但是有三个数是唯一出现的,找出这三个数。
点评:
3个数唯一出现,各不相同。由于x与a、b、c都各不相同,因此x^a、x^b、x^c都不等于0。具体答案请参看这两篇文章:1、http://blog.csdn.net/w397090770/article/details/8032898
2、http://zhedahht.blog.163.com/blog/static/25411174201283084246412/

22,9月19日,IGT面试:

你走到一个分叉路口,有两条路,每个路口有一个人,一个说假话,一个说真话,你只能问其中一个人仅一个问题,如何问才能得到正确答案?

点评:答案是,问其中一个人:另一个人会说你的路口是通往正确的道路么?

23,9月19日,创新工厂笔试题:

给定一整型数组,若数组中某个下标值大的元素值小于某个下标值比它小的元素值,称这是一个反序。
即:数组a[]; 对于i < j 且 a[i] > a[j],则称这是一个反序。
给定一个数组,要求写一个函数,计算出这个数组里所有反序的个数。

点评:归并排序,至于有的人说是否有O(N)的时间复杂度,我认为答案是否定的,正如老梦所说,下限就是nlgn,n个元素的数组的排列共有的排列是nlgn,n!(算法导论里面也用递归树证明了:O(n*logn)是最优的解法,具体可以看下这个链接:)。然后,我再给一个链接,这里有那天笔试的两道题目:http://blog.csdn.net/luno1/article/details/8001892

24 ,9月20日,创新工厂南京站笔试:

已知字符串里的字符是互不相同的,现在任意组合,比如ab,则输出aa,ab,ba,bb,编程按照字典序输出所有的组合。

点评:非简单的全排列问题(跟全排列的形式不同,abc 全排列的话,只有6个不同的输出:http://blog.csdn.net/v_july_v/article/details/6879101)。本题可用递归的思想,设置一个变量表示已输出的个数,然后当个数达到字符串长度时,就输出。

[cpp]  view plain copy
  1. //假设str已经有序,from 一直很安静    
  2. void perm(char *str, int size, int resPos)    
  3. {    
  4.     if(resPos == size)    
  5.     print(result);    
  6.     else    
  7.     {    
  8.     for(int i = 0; i < size; ++i)    
  9.         {    
  10.       result[resPos] = str[i];    
  11.       perm(str, size, resPos + 1);    
  12.     }    
  13.     }    
  14. }    

25,9月21日,小米,电子科大&西安交通大学笔试题:

我写了一个:

[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<vector>  
  3.   
  4. using namespace std;  
  5.   
  6. bool isValidSeq(char* str)  
  7. {  
  8.     char *input=str;  
  9.     if(input==NULL) return false;  
  10.     vector<char> v;  
  11.     while(*input!='\0')  
  12.     {  
  13.         if(v.size()<=0)  
  14.         {  
  15.             v.push_back(*input);      
  16.         }else  
  17.         {  
  18.             switch(*input)  
  19.             {  
  20.                 case '{':  
  21.                 case '(':  
  22.                 case '[':     
  23.                     v.push_back(*input);  
  24.                     break;  
  25.                 case '}':  
  26.                     if(*(v.end()-1)=='{')  
  27.                     {  
  28.                         v.pop_back();  
  29.                     }else  
  30.                     {  
  31.                         return false;  
  32.                     }  
  33.                     break;  
  34.                 case ')':  
  35.                     if(*(v.end()-1)=='(')  
  36.                     {  
  37.                         v.pop_back();  
  38.                     }else  
  39.                     {  
  40.                         return false;  
  41.                     }  
  42.                     break;  
  43.                 case ']':  
  44.                     if(*(v.end()-1)=='[')  
  45.                     {  
  46.                         v.pop_back();  
  47.                     }else  
  48.                     {  
  49.                         return false;  
  50.                     }  
  51.                     break;  
  52.             }  
  53.               
  54.         }  
  55.         input++;  
  56.     }  
  57.     if(v.size()>0) return false;  
  58.     else return true;  
  59. }  
  60.   
  61. char* fixSeq(char* str)  
  62. {  
  63.     char *input=str;  
  64.     if(input==NULL) return false;  
  65.     vector<char> v;  
  66.     char *ret=new char[50];  
  67.     int count=0;  
  68.     while(*input!='\0')  
  69.     {  
  70.         if(v.size()<=0)  
  71.         {  
  72.             v.push_back(*input);  
  73.             ret[count++]=*input;      
  74.         }else  
  75.         {  
  76.             switch(*input)  
  77.             {  
  78.                 case '{':  
  79.                 case '(':  
  80.                 case '[':     
  81.                     v.push_back(*input);  
  82.                     ret[count++]=*input;  
  83.                     break;  
  84.                 case '}':  
  85.                     if(*(v.end()-1)=='{')  
  86.                     {  
  87.                         v.pop_back();  
  88.                         ret[count++]='}';  
  89.                     }else  
  90.                     {  
  91.                         ret[count++]='{';  
  92.                         ret[count++]='}';         
  93.                     }  
  94.                     break;  
  95.                 case ')':  
  96.                     if(*(v.end()-1)=='(')  
  97.                     {  
  98.                         v.pop_back();  
  99.                         ret[count++]=')';     
  100.                     }else  
  101.                     {  
  102.                         ret[count++]='(';  
  103.                         ret[count++]=')';  
  104.                     }  
  105.                     break;  
  106.                 case ']':  
  107.                     if(*(v.end()-1)=='[')  
  108.                     {  
  109.                         v.pop_back();  
  110.                         ret[count++]='[';  
  111.                     }else  
  112.                     {  
  113.                         ret[count++]='[';  
  114.                         ret[count++]=']';  
  115.                     }  
  116.                     break;  
  117.             }  
  118.               
  119.         }  
  120.         input++;  
  121.     }  
  122.     return ret;   
  123. }  
  124. int main(int argc,char *argv[])  
  125. {  
  126.     char str[20]="({[({})]})";  
  127.     cout<<str<<":"<<isValidSeq(str)<<endl;  
  128.     char str2[20]="({[({(})]})";  
  129.     cout<<str2<<":"<<isValidSeq(str2)<<endl;  
  130.     cout<<"corret:"<<fixSeq(str2)<<endl;  
  131.     return 0;  
  132. }  

2,问:最后程序输出是多少?点评:此题有陷阱,答题需谨慎!

[cpp]  view plain copy
  1. void fun()    
  2. {    
  3.     unsigned int a = 2013;    
  4.     int b = -2;    
  5.     int c = 0;    
  6.     while (a + b > 0)    
  7.     {    
  8.         a = a + b;    
  9.         c++;    
  10.     }    
  11.     printf("%d", c);    
  12. }    

解答:无限循环,因为a是无符号类型,a+b的结果也是无符号类型,又因为a+b不可能等于0,所以a+b的结果永远大于0。

测试代码:

[cpp]  view plain copy
  1. int main(int argc,char *argv[])  
  2. {  
  3.     unsigned int a=1;  
  4.     a-=2;  
  5.     printf("a:%d,a>0:%d\n",a,a>0);      
  6.     return 0;  
  7. }  
输出结果:

a:-1,a>0:1

【科普:C运算转换规则】

自动转换遵循以下规则:

1)若参与运算量的类型不同,则先转换成同一类型,然后进行运算。

2)转换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量转成long型后再进行运算。

a.若两种类型的字节数不同,转换成字节数高的类型

b.若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型

3)所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。

4) char型和short型参与运算时,必须先转换成int型。

5)在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入。

隐式转换

隐式类型转换分三种,即算术转换、赋值转换和输出转换。

1.算术转换

进行算术运算(加、减、乘、除、取余以及符号运算)时,不同类型数招必须转换成同一类型的数据才能运算,算术转换原则为:

在进行运算时,以表达式中最长类型为主,将其他类型位据均转换成该类型,如:

(1)若运算数中有double型或float型,则其他类型数据均转换成double类型进行运算。

(2)若运算数中最长的类型为long型.则其他类型数均转换成long型数。

(3)若运算数中最长类型为int型,则char型也转换成int型进行运算。算术转换是在运算过程中自动完成的。

2.赋值转换

进行赋值操作时,赋值运算符右边的数据类型必须转换成赋值号左边的类型,若右边的数据类型的长度大于左边,则要进行截断或舍入操作。

下面用一实例说明:

charch;

inti,result;

floatf;

doubled;

result=ch/i+(f*d-i);

(1)首先计算ch/i,chint型,ch/iint型。

(2)接着计算f*d-i,由于最长型为double型,故fdouble型,idouble型,f*d-idouble型。

(3)(ch/i)(f*d-i)进行加运算,由于f*d-idouble型,故ch/idouble型,ch/i+(f*d-i)double型。

(4)由于resultint型,故ch/i+(f*d-i)doubleint,即进行截断与舍入,最后取值为整型。

3.输出转换

在程序中将数据用printf函数以指定格式输出时,当要输出的盐据类型与输出格式不符时,便自动进行类型转换,如一个long型数据用整型格式(%d)输出时,则相当于将long型转换成整型(int)数据输出;一个字符(char)型数据用整型格式输出时,相当于将char型转换成int型输出。

注意:较长型数据转换成短型数据输出时,其值不能超出短型数据允许的值范围,否则转换时将出错。如:

longa=80000;

printf("%d",a);

运行结果为14464,因为int型允许的最大值为3276780000超出此值,故结果取以32768为模的余数,即进行如下取余运算:

(80000-32768)-32768=14464;

输出的数据类型与输出格式不符时常常发生错误,如:

intd=9;

printf("%f",d);

floatc=3.2;

printf("%d",c);

将产生错误的结果。

同一句语句或表达式如果使用了多种类型的变量和常量(类型混用),C会自动把它们转换成同一种类型。以下是自动类型转换的基本规则:

1.在表达式中,charshort类型的值,无论有符号还是无符号,都会自动转换成int或者unsignedint(如果short的大小和int一样,unsignedshort的表示范围就大于int,在这种情况下,unsignedshort被转换成unsignedint)。因为它们被转换成表示范围更大的类型,故而把这种转换称为“升级(promotion)”。

2.按照从高到低的顺序给各种数据类型分等级,依次为:longdouble, double, float, unsigned long long, long long, unsigned long,long, unsigned int int。这里有一个小小的例外,如果longint大小相同,则unsignedint的等级应位于long之上。charshort并没有出现于这个等级列表,是因为它们应该已经被升级成了int或者unsignedint

3.在任何涉及两种数据类型的操作中,它们之间等级较低的类型会被转换成等级较高的类型。

4.在赋值语句中,=右边的值在赋予=左边的变量之前,首先要将右边的值的数据类型转换成左边变量的类型。也就是说,左边变量是什么数据类型,右边的值就要转换成什么数据类型的值。这个过程可能导致右边的值的类型升级,也可能导致其类型降级(demotion)。所谓“降级”,是指等级较高的类型被转换成等级较低的类型。

5.作为参数传递给函数时,charshort会被转换成intfloat会被转换成double。使用函数原型可以避免这种自动升级。



见17题。

填空:

1;s*c/(a+b),2:625,3:88,4:n*log(n):B

编程:

3:这里有一个解决方案,时间复杂度是m*m,空间复杂度是m:

[cpp]  view plain copy
  1. #include <STDIO.H>    
  2. #include <WINDOWS.H>    
  3.     
  4.     
  5. int Friends(int n, int m , int* r[]);    
  6.     
  7. int main(int argc,char** argv)    
  8. {     
  9.   int r[5][2] = {{1,2},{4,3},{6,5},{7,8},{7,9}};    
  10.      
  11.   printf("有%d个朋友圈。\n",Friends(0,5,(int**)r));    
  12.   return 0;    
  13. }    
  14.     
  15. int Friends(int n, int m, int* r[]) // 注意这里的参数很奇葩      
  16. {    
  17.      
  18.   int *p = (int*)malloc(sizeof(int)*m*3);    
  19.     
  20.   memset(p,0,sizeof(int)*m*3);    
  21.   int i = 0;    
  22.     
  23.   int iCount = 0;    
  24.     
  25.   int j = 0;    
  26.     
  27.   int * q = (int*)r; // 这里很巧妙  将二维指针 强转为一维指针    
  28.     
  29.   for (i=0;i<m;++i)    
  30.   {    
  31.     for (j=0;j<2;++j)    
  32.     {    
  33.       p[i*3+j]=q[i*2+j];   // 注意这里二维数组向一维数组的转换    
  34.     }    
  35.     
  36.     p[i*3+j] = 0;    
  37.   }    
  38.     
  39.   bool bFlag = false;    
  40.     
  41.   for (i=0;i<m;++i)    
  42.   {    
  43.     bFlag = false;    
  44.     if (p[i*3+2]==1)    
  45.     {    
  46.        bFlag = true;    
  47.     }    
  48.     p[i*3+2] = 1;    
  49.     for (j=0;j<m;++j)    
  50.     {    
  51.       if (i==j)    
  52.       {    
  53.         continue;    
  54.       }     
  55.          
  56.     
  57.       if (p[i*3]==p[j*3] ||    
  58.         p[i*3] == p[j*3+1] ||    
  59.         p[i*3+1] == p[j*3+0] ||    
  60.         p[i*3+1] == p[j*3+1])    
  61.       {    
  62.         if (p[j*3+2]==1)    
  63.         {    
  64.           bFlag = true;    
  65.         }    
  66.         p[j*3+2] = 1;    
  67.       }    
  68.     }    
  69.     
  70.     if (!bFlag)    
  71.     {    
  72.       ++iCount;    
  73.     }    
  74.   }    
  75.     
  76.   free(p);     
  77.       
  78.   return iCount;    
  79. }    


26,9月21日晚,海豚浏览器笔试题:

1、有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列,对于1<=i,j<=k,求k个最小的(ai+bj),要求算法尽量高效。

思路:a1+b1必为最小,记录两个递增序列,分别是ai+a[aj]和bj+b[bi],aj和bi分别是两个a和b在b和a中维护的下移个相加值的索引,具体实现见代码:

[cpp]  view plain copy
  1. #include<stdio.h>  
  2.   
  3. void findMinSum(int k,int a[],int b[])  
  4. {  
  5.     int count=1,i=0,j=0,aj=1,bi=1;  
  6.     printf("a%d+b%d=%d ",0,0,a[0]+b[0]);  
  7.     while(count<k)  
  8.     {  
  9.         int sum1=a[i]+b[aj];  
  10.         int sum2=b[j]+a[bi];  
  11.         if(sum1<=sum2)  
  12.         {  
  13.             printf("a%d+b%d=%d ",i,aj,sum1);  
  14.             if(a[i+1]-a[i]>b[aj+1]-b[aj]) aj++;  
  15.             else i++;  
  16.         }else  
  17.         {  
  18.             printf("a%d+b%d=%d ",j,bi,sum2);  
  19.             if(b[j+1]-b[j]>a[bi+1]-a[bi]) bi++;  
  20.             else j++;  
  21.         }  
  22.         count++;  
  23.   
  24.     }  
  25.     printf("\n");  
  26. }  
  27.   
  28. int main(int argc,char *argv[])  
  29. {  
  30.     int a[10]={1,3,5,7,8,9,11,12,13,16};  
  31.     int b[10]={2,4,6,8,9,13,15,17,19,21};  
  32.     findMinSum(10,a,b);  
  33.     return 0;  
  34. }  
时间复杂度为O(n);

2、输入:
L:“shit”“fuck”“you”
S:“shitmeshitfuckyou”
输出:S中包含的L一个单词,要求这个单词只出现一次,如果有多个出现一次的,输出第一个这样的单词
怎么做?

简单解法:保存一个大小与L中字符串数量一样的数组,用来记录对应字符串出现在S中的次数。

将S从头至尾扫一遍,每读入一个字符,判断以这个字符开头的字符串有没有出现在L中的字符串,有则相应的数组值+1,最后输出第一个数组值为1对应的L中的字符串。

27,9月22日上午,百度西安站全套笔试题如下:


简答题:

1,

数据库是以一定组织方式储存在一起的,能为多个用户共享的,具有尽可能小的冗余度的、与应用彼此独立的相互关联的数据集合。包括关系,网状,层次等类型的数据库。

死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态。

线程产生死锁的原因:系统资源不足;进程运行推进的顺序不合适;资源分配不当等

死锁的四个必要条件:
互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。
请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。
非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。
循环等待条件(Circular wait):系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。

死锁避免方法包括有序资源分配法和银行家算法等等。

2,

三个要素 : 封装, 继承,多态

面向对象设计不外乎遵循五大原则:

第一、单一职责原则,即一个类应该只负责单一的职责,而将其余的职责让其他类来承担,这样每个类之间相互协调来完成一件任务。
第二、开闭原则,即对扩展是开放的,对修改是封闭的,因此需要注重抽象的运用
第三、替换原则 ,子类应该可以替换在父类出现的任何地方
第四、依赖倒置原则,依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。
第五、接口分离原则,不要将一大堆方法都糅合在一个接口里面形成一个大而全的接口,要将他们按照职责和功能分离到多个小接口中去

3,

(1)块式管理。把主存分为一大块、一大块的,当所需的程序片段不在主存时就分配一块主存空间,把程序片段加载到主存,就算所需要的程序片段只有几个字节也只能把这块分配给它。优点:易于管理;缺点:浪费空间。

(2)页式管理。把主存分为一页一页的,每一页的空间要比一块一块的空间小很多,显然这种方式的空间利用率要比块式管理高出很多。

(3)段式管理。把主存分为一段一段的,每一段的空间又要比一页一页的空间小很多,这种方法在空间利用率上比页式管理高出很多,但也有另外一个缺点,一个程序片段可能会被分为几十个段,这样很多时间就会浪费在计算每一段的物理地址上。(I/O操作)

(4)段页式管理。结合了段式管理和页式管理的优点。把主存分为若干页,每一页又分为若干段。


算法设计:

1,1000场?

2,10盏:1,4,9,16,25,36,49,64,81,100

原理:状态改变奇数次的灯最后是开的,而灯的改变次数等于它的约数,例如10的约数是1,2,5,10,因此在第1,2,5,10次被改变,最后是灭的,所以最后开的灯其编号约数是奇数,而约数为奇数的数是完全平方数,因此最后编号为平方数的10盏灯开着。

3,

为了方便讨论,先设计几个变量。n表示所有元素的数量,n=100000。m表示数组的数量,m=20,k选择最大的元素数量,k=500。

解决这个问题主要有2个思路。

1、建个m的堆,搞多路归并,复杂度log(m)*k
2、二分该数,并在m个数组中验证,复杂度m*log(n)*log(n/m) + K,详细说一下就是,先从一个数组中找一个数,然后在m个数组二分找到该数的位置,并统计有多少数大于该数。如果<k(500),则再根据位置二分,找一个更大一些的数。否则找一个更小的数,重复上面的操作。每次统计的复杂度为m*log(n/m),总共需要迭代log(n)次,最后输出需要K,所以总共m*log(n)*log(n/m) + K

系统设计题:

28,9月22日,微软笔试:

T(n)=1(n<=1),T(n) = 25*T(n/5) + n^2,求算法的时间复杂度。

思路:T(n)=25*(25*T(n/25)+(n/5)^2)+n^2=25^2*T(n/(5^2))+2*n^2=25^(log(n)/log5)+(log(n)/log5)*n^2=O(n^2*log(n))

更多题目请参见:http://blog.csdn.net/wonderwander6642/article/details/8008209

29,9月23日,腾讯校招部分笔试题

解答:

11:C,12:C(一样?),13:B,14:A,15:D,16:A,17:C,18:A,19:B

25:O(nlog(n)),O(n)

26:42(计算公式:[1/(n+1)]*C(n-2n),即2n取n的组合数除以n+1)

27:abcd-*e/+f-

三,1:不会javascript

2:建立n个256大小的数组用来保存每个字符串中的字符相应的重复个数,之后按重复度大小排序,接着再利用这n个数组对原字符串数组排序。

时间复杂度:O(n*n*logn),空间复杂度O(n)。

四:1:哈希分桶+最小堆

2:数据库设计,可以采用HBase

30,9月23日,搜狗校招武汉站笔试题:

已知计算机有以下原子操作
1、 赋值操作:b = a;
2、 ++a和a+1;
3、for( ){ ***}有限循环;
操作数只能为0或者正整数,定义函数,实现加减乘操作

解答:加法和乘法利用循环可以实现,减法如下:

[cpp]  view plain copy
  1. sub(int a,int b)  
  2. {  
  3.    int c=0;  
  4.    for(int i=b;i>a;i--)  
  5.       c++;  
  6. }  



 附:9月15日,搜弧校招笔试题:http://blog.csdn.net/hackbuteer1/article/details/8015964

31,搜狗校招笔试题:

100个任务,100个工人每人可做一项任务,每个任务每个人做的的费用为t[100][100],求一个分配任务的方案使得总费用最少。

点评:匈牙利算法,可以看看这篇文章:http://www.byvoid.com/blog/hungary/,及这个链接:http://www.51nod.com/question/index.html#!questionId=641

32,9月24日,Google南京等站全套笔试题如下:




1.1:B,亲测,我自己的电脑运行了3秒

1.2:D

1.3:B

1.4:A

就是求x1+x2+x3+x4=25的大于等于0的解,相当于将25个相同的求放进4个盒子里,盒子不一样,求所有可能的放法:

笨办法:只有1个数不为零0解的个数:4

方便书写,规定C(a,b)为对b中取a的的组合数。

有2个数不为零0解的个数:C(2,4)*C(1,24)

有3个数不为零0解的个数:C(3,4)*C(2,24)

全不为0:C(3,24)

最后结果:4+144+1104+2024=3276;所以选A

1.5:D

1.6:B

1.7:D

1.8:C

1.9:A<B?>

1.10:D

2.1:

[cpp]  view plain copy
  1.  if (a <= b) {    
  2.     if (b <= c)    
  3.         return b;    
  4.     else {    
  5.         if (a <=c)    
  6.             return c;    
  7.         else    
  8.             return a;    
  9.         }    
  10. }    
  11. else {    
  12.     if (a <= c)    
  13.         return a;    
  14.     else {    
  15.         if (b <= c)    
  16.             return c;    
  17.         else    
  18.             return b;    
  19.         }    
  20. }   

2.2:本质上采用快速排序,比较函数时候有些变化,需考虑比较元素在哦key里的次序,代码如下:

[cpp]  view plain copy
  1. #include "stdio.h"  
  2. #include "stdlib.h"  
  3. #include "string.h"  
  4.   
  5. void quick_sort(char* data,int s,int e,const char *key,int lk);  
  6. int partition(char* data,int s,int e,const char *key,int lk);  
  7. void sort(char *data,int ld,const char *key,int lk);  
  8. int compare(char a,char b,const char *key,int lk);  
  9. void main()  
  10. {  
  11.     char data[256]={"aaakhlqkxcvhiuosadkjdfmbnvcjkszghkljeawhfmkbdsaklgh"};  
  12.     char key[7]={"zxonm"};  
  13.     sort(data,strlen(data),key,strlen(key));  
  14.     printf("after sort:%s\n",data);  
  15. }  
  16. //对data用key进行排序  
  17. void sort(char *data,int ld,const char *key,int lk)  
  18. {  
  19.     quick_sort(data,0,ld-1,key,lk);  
  20. }  
  21. //判断a和b在key里位置的大小  
  22. int compare(char a,char b,const char *key,int lk)  
  23. {  
  24.     int pos_a=-1,pos_b=-1;  
  25.     for(int i=0;i<lk;i++)  
  26.     {  
  27.         if(key[i]==a) pos_a=i;  
  28.         if(key[i]==b) pos_b=i;  
  29.     }  
  30.     if(pos_a==-1&&pos_b==-1)//都不在  
  31.     {  
  32.         return a-b;  
  33.     }else if(pos_a!=-1&&pos_b==-1)//a在b不在  
  34.     {  
  35.         return -1;  
  36.     }else if(pos_a==-1&&pos_b!=-1)//a不在b在  
  37.     {  
  38.         return 1;  
  39.     }else//都在  
  40.     {  
  41.         return pos_a-pos_b;  
  42.     }  
  43. }  
  44. void quick_sort(char* data,int s,int e,const char *key,int lk)  
  45. {  
  46.     if(s>e) return;  
  47.     int p=partition(data,s,e,key,lk);  
  48.     quick_sort(data,s,p-1,key,lk);  
  49.     quick_sort(data,p+1,e,key,lk);  
  50. }  
  51. int partition(char* data,int s,int e,const char *key,int lk)  
  52. {  
  53.     int l=s-1,r=s;  
  54.     while(r<e)  
  55.     {  
  56.         if(compare(data[r],data[e],key,lk)<0)  
  57.         {  
  58.             l++;  
  59.             int t;  
  60.             t=data[l];  
  61.             data[l]=data[r];  
  62.             data[r]=t;  
  63.         }  
  64.         r++;  
  65.     }  
  66.     int t;  
  67.     t=data[++l];  
  68.     data[l]=data[e];  
  69.     data[e]=t;  
  70.     return l;  
  71. }  

空间复杂度O(1),时间复杂度O(nlongn).

2.3:
思路:由于题目只强调时间复杂度尽可能低,且n的取值范围相对较小[1,1000], 考虑用空间换时间。
设置一个大小为1000×1000的二维数组: int num[1000][1000](内存开销为4MB)
预处理阶段,每输入一个矩形:[x1,y1],[x2,y2],则 for i from x1 to x2
for j from y1 to y2
num[i][j]++;
预处理阶段完毕,则对每一个query:[x,y],直接返回num[x][y]的值,使得查询时间复杂度为O(1).

33,读者来信,提供的几个hulu面试题:  

9月19号,hulu电面:
问题1 两个骰子,两个人轮流投,直到点数和大于6就停止,最终投的那个人获胜。问先投那个人获胜概率?

我也不会.....

问题2 平面上n个圆,任意两个都相交,是否有一条直线和所有的圆都有交点。

好吧好吧...9月22号,上午hulu面试问题1 100个人,每人头上戴一顶帽子,写有0..99的一个数,数可能重复,每个人都只能看到除自己以外其他人的帽子。每个人需要说出自己的帽子的数,一个人说对就算赢。

点评:参考答案请看这个链接:http://www.51nod.com/question/index.html#!questionId=642

问题2 n台机器,每台有负载,以和负载成正比的概率,随机选择一台机器。「原题是希望设计O(1)的算法(预处理O(n)不可少,要算出每台机器的比例),因为非O(1)的话,就trivial了:可以产生随机数例如[0,1)然后,根据负载比例,2分或者直接循环检查落入哪个区间,决定机器。 面试官想问,有没更好的办法,避免那种查找。即能否多次(常数次)调用随机函数,拟合出一个概率分布

问题3 行列都递增的矩阵,求中位数。

点评:http://www.51nod.com/question/index.html#!questionId=643http://blog.csdn.net/v_july_v/article/details/7085669(杨氏矩阵查找问题)

总结:二分查找,线性统计

34,西安百度软件研发工程师:

一面(2012.9.24):
问的比较广,涉及操作系统、网络、数据结构。比较难的就2道题。
(1)10亿个int型整数,如何找出重复出现的数字;

大数据分段哈希进文件,然后小数据读入内存哈希统计重复

(2)有2G的一个文本文档,文件每行存储的是一个句子,每个单词是用空格隔开的。问:输入一个句子,如何找到和它最相似的前10个句子。(提示:可用倒排文档)。

二面(2012.9.25):
(1)一个处理器最多能处理m个任务。现在有n个任务需要完成,每个任务都有自己完成所需的时间。此外每个任务之间有依赖性,比如任务A开始执行的前提是任务B必须完成。设计一个调度算法,使得这n这任务的完成时间最小;

思路:根据任务顺序和时间画出AOE图,求出关键路径,使用多个处理器集中完成关键活动及周边的活动,使任务完成时间最短。

(2)有一个排序二叉树,数据类型是int型,如何找出中间大的元素;
思路:从根节点开始无限求右孩子,直到右孩子为空为止。

(3)一个N个元素的整形数组,如何找出前K个最大的元素。
思路:利用k个元素的最小堆

(4)给定一个凸四边形,如何判断一个点在这个平面上。

http://www.51nod.com/question/index.html#!questionId=669

运维部(2012.9.27):
(1)堆和栈的区别;

- -!这种题就不回答了
(2)问如何数出自己头上的头发。

- -!这种非人类的题目就不回答了

 35:9月25日,人人网笔试题:


  1. 点评:参考答案请见,http://www.51nod.com/question/index.html#!questionId=671

36,9月25日晚,创新工场校园招聘北邮站笔试:

选择:

1:D,2:B,3:B,4:C(哲学家进餐问题),5:B ,6:A(http://www.cnblogs.com/mycapple/archive/2012/08/09/2629608.html)

简答:

1:Tire树

2:#define EXB(arg) (((arg)&0xaaaaaaaa)>>1)|(((arg)&0x55555555)<<1)

3:创新工厂

      创新工厂

(引用与指针问题)

4:ABCDGHFE

编程题:

1:思路:先单个单词翻转,再整个字符串翻转。

我写了一个:

[cpp]  view plain copy
  1. #include "stdafx.h"  
  2. #include "string.h"  
  3.   
  4. void Reverse(char *data,int start,int end);  
  5. void ReverseString(char *data,int n)  
  6. {  
  7.     int start=0,end=0;  
  8.     while(start<n&&end<n)  
  9.     {  
  10.         while(data[start]==' ') start++;  
  11.         end=start+1;  
  12.         while(data[end]!=' '&&end<n) end++;  
  13.         Reverse(data,start,end-1);  
  14.         start=end+1;  
  15.     }  
  16.     Reverse(data,0,n-1);  
  17. }  
  18. void Reverse(char *data,int start,int end)  
  19. {  
  20.     while(start<end)  
  21.     {  
  22.         char t=data[start];  
  23.         data[start]=data[end];  
  24.         data[end]=t;  
  25.         start++;  
  26.         end--;  
  27.     }  
  28. }  
  29.   
  30.   
  31. int _tmain(int argc, _TCHAR* argv[])  
  32. {  
  33.     char str[256]="Welcome to Innovation works.";  
  34.     printf("before reverse:%s\n",str);  
  35.     ReverseString(str,strlen(str));  
  36.     printf("after reverse:%s\n",str);  
  37.     return 0;  
  38. }  

2:我的思路:用vit[i]/hap[i],计算出每种食品平均一点体力带来多少欢乐,记为avr[i],并按ave[i]从大到小排序,每种食品只带一次,因此从大到小依次取食品,同时体力m减去对应消耗值,体力不够时取下一个食品直到体力为0或者遍历完所有食品为止,时间复杂度为O(nlog(n))。

代码很简单略过。

37,9月25日,小米大连站笔试题:

1一共有100万,抽中的2万,每月增加4万,问20个月能抽中的概率为:?

不明题意,4万加的是啥?

2 for(int i=0;i<strlen(s);i++){n+=I;}时间复杂度O(n)
这难道不是一个陈述句?

3 手机wifi(A)….wifi ap….局域网(B)…..路由器…ADSL(C)…..互联网…..服务器
断掉上述ABC哪些点TCP链接会立刻断掉?
我的答案:A(B或C断开可能发生重连)

4 12345入栈,出栈结果 21543 31245 43215 12534 可能的为?(第一个和第三个)
答案:21543和43215不解释,括号里已经给出了答案- -#

5 x^n+a1x^n-1+…+an-1x+an,最少要做—乘法?题目中a1,a2,an为常数。

(n-1)+(n-1)+(n-2)+...+2+1=(n*n+n-2)/2.

 38,9月26日,百度一二面:

1、给定一数组,输出满足2a=b(a,b代表数组中的数)的数对,要求时间复杂度尽量低。

思路1:先从小到大排序,再从头开始遍历找到第一个最接近最小数两倍的数,左右指针分别为l和r,开始2):
2):r往后遍历,当a[l]=a[r]时输出数对,l++,r++;
当a[r]>a[l]时l++
当a[r]<a[l]时r++
直到r>n为止
时间复杂度:O(nlogn),空间复杂度O(1)
思路2:构造一个bit数组,使得bit数组大小为原数组大小最大数的两倍,遍历使得以数据数组对应数字为索引的bit数组值为1,再遍历一次,直接查看当前数据数组值的两倍对应的bit数组位置值是否为1,是则输出。
空间复杂度:与数组最大值有关,最小为O(2*n),时间复杂度,O(n)
思路3:根据原数据数组构造哈希表,再判断2倍数组值是否存在哈希表中,比较中肯,时间复杂度:O(N),空间复杂度O(N)。

2 搜索引擎多线程中每个线程占用多少内存?如果搜索引擎存储网页内存占用太大怎么解决?
这个真不会,搜索引擎小白....

3、有很多url,例如*.baidu.com,*.sina.com ......现在给你一个sports.sina.com 快速匹配出是*.sina.com。
原作者点评:老题,此前blog内曾整理过。
难道是用后缀树???也不给个链接.....- - #

4 找出字符串的编辑距离,即把一个字符串s1最少经过多少步操作变成编程字符串s2,操作有三种,添加一个字符,删除一个字符,修改一个字符(只要听过编辑距离,知道往动态规划上想,很快就可以找到解法)。
  1. 点评:请看链接:http://blog.csdn.net/Lost_Painting/article/details/6457334
核心动态规划算法:
[java]  view plain copy
  1. public static int[,] Calculate(char[] First, char[] Second)    
  2.         {    
  3.             int lenFirst = First.Length + 1;    
  4.             int lenSecond = Second.Length + 1;    
  5.             int[,] matrixResult = new int[lenFirst, lenSecond];    
  6.             for (int i = 0; i < lenFirst; i++) matrixResult[i, 0] = i;    
  7.             for (int j = 0; j < lenSecond; j++) matrixResult[0, j] = j;    
  8.             for (int i = 1; i < lenFirst; i++)    
  9.             {    
  10.                 for (int j = 1; j < lenSecond; j++)    
  11.                 {    
  12.                     if (First[i - 1] == Second[j - 1])    
  13.                     {    
  14.                         matrixResult[i, j] = matrixResult[i - 1, j - 1];    
  15.                     }    
  16.                     else    
  17.                     {    
  18.                         matrixResult[i, j] = new int[] {matrixResult[i - 1, j] + 1    
  19.                                                         , matrixResult[i , j-1] + 1    
  20.                                                         , matrixResult[i - 1, j-1] + 1    
  21.                                                        }.Min();    
  22.                     }    
  23.                 }    
  24.             }    

for (int i = 0; i < lenFirst; i++) matrixResult[i, 0] = i;

for (int j = 0; j < lenSecond; j++) matrixResult[0, j] = j;

这两行是初始化,代表最坏情况下的编辑次数,即从无到有直接插入N或M次

[java]  view plain copy
  1. matrixResult[i, j] = new int[] {matrixResult[i - 1, j] + 1    
  2.                                                        , matrixResult[i , j-1