您的位置:首页 > 其它

2014校园招聘各大公司笔试题目

2013-10-14 11:31 447 查看
一:有道。给定一个数字,返回其字典序排列的下一个值

比如给定132,其有四个数字组成‘1’,‘2’,‘3’,那么这三位数字组成的字典序全排列123,132,213,231,312,321。即其排列是从小到大排序的。输入给出的是132,那么应该返回的数字就是213。

思路:

其实这道题还是很简单的,但是需要知道一些其他知识储备。你应该知道全排列的生成算法,应该了解一下字典序全排列与普通全排列的区别。如果知道之后,那么该题目还是比较容易可以写的出来的。

全排列的生成算法比较多的。在这里贴出一种递归实现。

void genePermu(int A[], int i, int n){
if(i == n -1){
for(int k = 0; k < n; k ++){
cout << A[k] << " ";
}
cout << endl;
return;
}else{
for(int k = i; k < n; k ++){
mySwap(A[k], A[i]);
genePermu(A, i + 1, n);
swap(A[k], A[i]);
}
}
}


             但是上述算法的问题是,它不能生成字典序的全排列。所以还要对上述代码进行一定的修改才可以。

二:有道。题目是leetcode上的一道题目,leetcode上面是max container water。有道的题目是给出一个数组,按照数组中的值在二维平面做图,问可以围成的最大面积。

一个比较好的回答,可以参考连接中的回答。
http://www.cnblogs.com/lichen782/p/leetcode_Largest_Rectangle_in_Histogram.html

三:腾讯。题目是给定两个整形数组,求这个整型数组中最大的交集,即两个数组中有几个重复的数字。
             应该说解法还是很多的,有O(n^2)的两编遍历,也可以通过空间换取时间的O(n)。

简单说下,空间换时间。可以通过遍历第一个数组,把所有数字放进一个map,然后遍历第二个数组,如果map中有该数值,说明是交集中的一个,记录了该数值,继续遍历。

四:完美。求两个字符串的最短编辑距离。针对两个字符串只能做交换次序,增上一个字符,求能把两个字符变成相同字符,所需要的最小操作次数。

开始完全没思路,除了遍历还是遍历,后来搜索答案,发现这还是个非常经典的题目。题目是采用了动态规划的解法。

 五:最短摘要算法。从一个长字符串中查找包含给定字符集合的最短子串。例如,长串为“aaaaaaaaaacbebbbbbdddddddcccccc”,字符集为{abcd},那么最短子串是“acbebbbbbd”。

背景介绍:

  摘要是指以简明扼要的文句,将某种文献的主要内容,正确无误地摘录出来。从定义也可以看出针对一个文章的摘要肯定会有短有长,但是长短的不同也就代表这数据量的不同。针对搜索引擎来说,当你输入一个搜索词语之后,对于返回的搜索结果中会有部分的网页正文内容,这部分的正文内容就是该网页的摘要。对于一个比较短的摘要,那么搜索结果需要加载的时间就会比较少一点。所以,这就希望每个网页的摘要都是最短的。这就需要一个最短摘要的算法。

算法介绍:

  最短摘要的生成可以通过一道算法的题目去理解。在编程之美上,有这样一道公司的笔试面试题目是和最短摘要相关的。从一个长字符串中查找包含给定字符集合的最短子串。例如,长串为“aaaaaaaaaacbebbbbbdddddddcccccc”,字符集为{abcd},那么最短子串是“acbebbbbbd”。

  反映到搜索引擎的情况就是:输入搜索词abcd,搜索到一个网页内容为“aaaaaacbebbbbbdddddddcccccc”的网页,那么搜索引擎不可能返回一整个网页,所以这时候就要针对原网页与搜索词生成一个原网页的最短摘要。

算法思想:首先pBegin指针从字符串头开始开始搜索,直到找到包含所有给定字符串位置pEend;下一步上前移动pBegin,并测试pBegin与pEnd之间的字符串是否包含给定字串,一直移动pBegin到不包含给定字符串,这时候判断当前子串与已经找到的子串的长度大小,然后随时更新最短子串的位置;重复上述两部操作,知道pEnd等于原串的长度,到达末尾。

  C++实现,借助了hash_map的数据结构,让查找可以在O(1)内完成。

 

#include <iostream>
#include <string>
#ifdef __GNUC__ //to determine which compiler is
#include <ext/hash_map>
#else
#include <hash_map>
#endif
using namespace std;
using namespace __gnu_cxx;

const string str = "aaaaaaaaaacbebbbbbdddddddcccccc";

bool isExist(int pBegin, int pEnd, hash_map<char, int> hash){
bool isExist = true;
hash_map<char, int> tmp;
for(int i = pBegin; i < pEnd; i ++){
tmp[str[i]] = 1;
}
hash_map<char, int>::iterator it = hash.begin();
for(; it != hash.end(); it++){
if(tmp.find(it -> first) != hash.end()){
continue;
}
isExist = false;
break;
}
return isExist;
}

string shortestAbstract(string substr){
string strstr;
int pBegin = 0;
int pEnd = substr.size(); //the end of abstract
int nLen = str.size();//the length of src str
int shortest = nLen;

int resultBegin = 0; //the begin of the final abstract
int resultEnd = 0;// the end of the final abstract

hash_map<char, int> hash;
for(int i = 0; i < substr.size(); i ++){
hash[substr[i]] = 1;
}
while(true){
//find the pEnd from begin
while(!isExist(pBegin, pEnd, hash) && pEnd < nLen){pEnd ++;}
//move begin forward and judge whether it contains the given str
while(isExist(pBegin, pEnd, hash))
{if(pEnd - pBegin < shortest){
shortest = pEnd - pBegin;
resultBegin = pBegin;
resultEnd = pEnd -1;    }
pBegin ++;}
if(pEnd >= nLen){ break;    }
}   cout << "resultBegin:" << resultBegin << endl;
cout << "resultEnd:" << resultEnd << endl;
strstr = str.substr(resultBegin, (resultEnd - resultBegin + 1));
return strstr; }
int main(){
string substr;
cin >> substr;
string result = shortestAbstract(substr);
cout << result << endl;
system("pause");
return 0;}


六 :给出一个列表,让求倒数第K个节点的值

第一种办法,思想其实很简单,我们可以现从头遍历整个列表,获取总过多少个节点,然后求得倒数第K个节点位置就可以了。然后重新遍历,获取倒数第K个节点位置。思想很简单,但是也存在弊端,就是需要遍历两次列表,才可以。

另一种解决办法是,使用两个指针都指向头节点。然后两个指针的其中一个指针B向后遍历K个节点,然后两个节点A、B同时向后遍历。因为A与B之间相差K个位置,所以当B节点达到终点的时候,A节点正好是倒数第K个位置。这样就不需要遍历两次位置了。

下面给出代码实现:

typedef struct Node{
       char data;
       Node *next;       
}Node;

int length(const Node *pHead){
     if(pHead == 0){
              printf("null head");
             return -1;      
     }
     Node *pNext = (Node *) pHead;
     int length = 0;
     while(pNext != NULL){
             pNext = pNext -> next;
              length ++;
     }
     return length;    
}

Node *find(const Node *pHead, int lastK){
int len = length(pHead);//这个时候其实已经遍历一遍,我们可以使用一个地方记录列表长度
if(lastK > len){
printf("wrong num");
return NULL;
}else{
Node *p1 = (Node *) pHead;
Node *p2 = p1;
for(int i = 0;i < lastK; i ++){
p2 = p2 -> next;
}
while(p2 != NULL){
p2 = p2 -> next;
p1 = p1 -> next;
}
return p1;
}
}

上面代码是直接采用了第二种方法的思想。但是,没有考虑的是,当K在前半部分的时候的场景。从第二种算法思想可以看到当K位于列表的后半部分的时候,算法效果比较好;但是当位于前半部分的时候,效率比较低。所以算法改进可以在遍历前判断K的位置,当K大于列表长度一半的时候,可以直接从头使用一个指针遍历。

还未考虑的地方是,当列表是环形指针列表的时候,算法需要怎样的改进。

七:给出两个排好序的列表,求两个列表的交集(百度)

示例

A:1 -> 4 -> 7 ->10 ->13

B:5 -> 8 ->10->13

那么输出结果就为10->13

根据题目给出的信息我们可以知道,两个列表的末尾肯定是相结合的。所以我们可以使用两个指针分布指向第一个列表和第二个列表,然后走如下操作。

首先查找两个列表长度的相差几个元素,让长的列表的指针向后移动到两个列表长度相同。然后同时移动两个指针分别比较,指针指向元素是否相等,直到列表结尾。

这个题目也有很多变种。上面考虑的是相邻的元素,也可以考虑不相邻的元素,即两个排序列表中都含有的元素。

题目描述:

给定字符串,输出括号是否匹配,例如,"()" yes;")(" no;"(abcd(e)" no;"(a)(b)" yes。

算法:

使用的是递归解决,如果使用栈的话,是比较好解决的,当是括号的左括号就push,遇到右括号就把栈顶pop。在这里没使用栈,使用了数组,不过是在第一位设置了一个标志位,用来标识是否是结束。然后当是左括号的时候添加进数组,指针加1,当是右括号的时候,判断当前指针是否是左括号,然后根据情况决定当期输入是否合法或者相应的指针减1;

#include <iostream>
using namespace std;
bool isRight(char *str, char *array, int size){
if(str == 0){
return false;
}
if(size == 0 && *array == '0'){
return true;
}else{
if(size == 0){
return false;
}else{
if(*str == ')'){
if(!(*array-- == '(')){
return false;
}
}else if(*str == '('){
array++;
*array = '(';
}
str ++;
size --;
return isRight(str, array, size);
}
}
}
int main(){
string str= "";
cin >> str;
char *in = (char *)str.data();
char *array = new char[(strlen(in) / 2) + 1];
array[0] = '0';//把地位设置为标志位
bool result = isRight(in, array, strlen(in));
cout << "result is " << result <<endl;
delete[] array;
system("pause");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息