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

  • 一:有道。给定一个数字,返回其字典序排列的下一个值

比如给定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。有道的题目是给出一个数组,按照数组中的值在二维平面做图,问可以围成的最大面积。
一个比较好的回答,可以参考连接中的回答。
  • 三:腾讯。题目是给定两个整形数组,求这个整型数组中最大的交集,即两个数组中有几个重复的数字。

             应该说解法还是很多的,有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");
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值