【100题】第八十一 ~ 第九十题

81)第1组百度面试题

1)题目:一个int数组,里面数据无任何限制,要求求出所有这样的数a[i],其左边的数都小于等于它,右边的数都大于等于它。能否只用一个额外数组和少量其它空间实现。

分析: 题意说明如果对数组排序的话,a[i] 就应该排在 i 的位置 只有这样才能保证左边的数都小于等于它,右边的数都大于等于它

解答:新建另一数组b[ ],将原数组拷贝到新数组,然后对新数组排序。所有a[i] = b[i] 的数为所求

2)题目:一个文件,内含一千万行字符串,每个字符串在1K以内,要求找出所有相反的串对,如abc 和cba。

2^20 =1048576 ~一百万

一千万 ~ 2^23

所以总共 约10G 左右数据,完全装入内存处理,不太可能。

方法一:暴力查找 时间复杂度 O(n^2)

方法二:Hash法

第一趟,依次读入文件中字符串(分批读入内存),然后Hash处理

第二趟,依次读入文件中字符串,先做逆序处理,再Hash处理,然后去Hash表中查找有无对应字串的Hash。


3)STL的set 用什么实现的?为什么不用hash?

红黑树(RB-Tree)平衡二叉搜索树,自动排序的效果不错

Hash浪费空间,随着元素的增长,Hash表可能要变化,或者搜索性能下降。

82)第2组百度面试题--》参考

1)给出两个集合A和B,其中集合A={name},集合B={age、sex、scholarship、address、...},

要求:

问题1、根据集合A 中的name 查询出集合B 中对应的属性信息;

问题2、根据集合B 中的属性信息(单个属性,如age<20 等),查询出集合A 中对应的name。

解答:

问题1、

方法一:数据库方法

问题1, select * from A,B where A.name = B.name;

问题2 ,select name from A,B where A.name =(select name from B where age<20 group by name);

点评:百度面试题,写两个SQL语句??这样可以?

方法二:直接采用STL 中的Map<key,value> 其中 key 记录A中的name,而value 记录集合B的属性向量信息。通过key直接查询B中对应属性的信息。

MultiMap<key,value> 允许key可以重复,感觉这里name应该不重复

方法三:(Java而不是C++ STL) 为了提高查询效率,就是给出name可以迅速查找出对应B中向量的信息,采用hashtable<key,value>

HashMap是在hashtable的基础上演变而来的,Hashtable是线程安全;HashMap是线程不安全的;HashMap允许多线程操作所以HashMap更快!

查询数据采用 get(key)

方法四:自定义映射关系,struct {set,vector} 这样做能提高查询效率么?

问题2、

方法一:暴力法,遍历B 判断age< 20 则去A中查寻对应 name (效率低)

方法二:遍历一遍A中name 存放Hash表中,然后 遍历B age <20 则取name 的Hash值 去Hash表中查找,有则输出。

2)给出一个文件,里面包含两个字段{url、size},即url 为网址,size 为对应网址访问的次数

要求:

问题1、利用Linux Shell 命令或自己设计算法,查询出url 字符串中包含baidu子字符串对应的size字段值;

问题2、根据问题1 的查询结果,对其按照size 由大到小的排列。(说明:url数据量很大,100 亿级以上)

解答:

用不熟悉的awk 命令

1. shell: awk /baidu/ { print $2 }FILE

2. shell: awk /baidu/ {print $2}FILE | sort -nr >> Result_FILE //-r 颠倒指定顺序 -n按算术值对数字字段排序

用熟悉的grep命令

1. grep "baidu" baidu.txt

2. grep "baidu" baidu.txt > baidu2.txt 然后 sort -rn baidu2.txt >>baidu3.txt

ls -l | sort -rn baidu2.txt //查看排序后的结果

用算法解决

1,KMP算法解决字符串匹配问题(next数组) 先查找所有匹配"baidu"的url

2,对1中结果 中的size 转化为 整形 然后排序 (希尔、快排、堆)

3)测试题:如何测试一部手机或者如何测试一台露天售货机(需要测试硬件部分和软件部分)

其实测试,只要把握三条最基本的原则:1、等价划分;2、边界值测试;3、经验评估查错(当然啦,经理还需要考虑效益、进度等经济因素)

然后遵照这些原则进行分析、思考测试用例、总结。

解答:

例如本次测试一部手机,先划分为硬件与软件测试两部分。

1)硬件测试如温度、按键、开机、抗摔、抗震、抗摸等等物理特性;

2)软件部分需要细划分为系统软件与应用软件两部分,因为系统软件和应用软件的功能和使用频度不一样,

因此需要考虑测试的轻重缓急,由重点软件(如电话薄)到次重点软件(如电子书)再到非重点软件(如游戏),由使用频繁到较频繁再到较少使用等频度划分,

如此依次划分进行计划、安排、进行测试。列举硬件、软件;系统软件、应用软件;百度软件和其它应用软件;以及在Android手机上详细测试百度手机输入法等测试过程。

核心思路:等价划分——》边界值测试——》凭经验重点测试经常或较易出bug的地方(如果大家想深入学习软件测试的核心思想和方法,推荐一本经典——大师级的Myers编写的《The Art of Software Testing》(软件测试的艺术)

83)第3组百度面试题

1)今年百度的一道题目

百度笔试:给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数。要求:空间复杂度O(1),时间复杂度为O(n)。

思路:借鉴快速排序一次换分思想,从左边找偶数,右边找奇数,然后交换,直到遍历所有元素。

2)百度笔试题

用C语言实现函数void * memmove(void *dest, const void *src, size_t n)。memmove 函数的功能是拷贝src所指的内存内容前n 个字节到dest 所指的地址上。

分析:

由于可以把任何类型的指针赋给void类型的指针, 这个函数主要是实现各种数据类型的拷贝。

这里区别于strncpy(void *dest, const void *src, size_t n) ; 这个复制字符串的函数是遇到 ‘\0’则停止或者复制长度达到 n 。

区别于 memcpy(void *dest , const void *src, size_t n); 对于src 和 dest 重叠情况 返回NULL

而memmove 实现的功能:是由src所指内存区域复制count个字节到dest所指内存区域。

说明:而src和dest所指内存区域可以重叠,但复制后dest内容会被更改。函数返回指向dest的指针。

使用:

char *str1="12345";

char *str2=(char *)malloc(sizeof(char)*strlen(str1));

memmove(str2,str1,strlen(str1));

memmove的处理措施:

(1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝

(2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝

(3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝

memcpy的实现

void* memcpy(void* dest, const void* src, size_t n)  
{ 
    char*      d = (char*) dest; 
    const char*  s = (const char*) src; 
    while(n-–)  
       *d++ = *s++; 
    return dest; 
}


memcpy的实现

void* memmove(void* dest, const void* src, size_t n) 
{ 
    char*     d  = (char*) dest; 
    const char*  s = (const char*) src; 
   
    if (s>d)  
    { 
         // start at beginning of s 
         while (n--) 
            *d++ = *s++; 
    } 
    else if (s<d) 
    { 
        // start at end of s 
        d = d+n-1; 
        s = s+n-1; 
   
        while (n--) 
           *d-- = *s--; 
    } 
    return dest; 

示意图:

(1)内存低端 <-----s-----> <-----d-----> 内存高端 start at end of s
(2)内存低端 <-----s--<==>--d----->      内存高端 start at end of s
(3)内存低端 <-----sd----->              内存高端 do nothing
(4)内存低端 <-----d--<==>--s----->      内存高端 start at beginning of s
(5)内存低端 <-----d-----> <-----s-----> 内存高端 start at beginning of s


84)第4组百度面试题

2010 年3 道百度面试题[相信,你懂其中的含金量]

1)a~z 包括大小写与0~9 组成的N 个数, 用最快的方式把其中重复的元素挑出来。

这里题意应该是N个字符,则采用Hash[256] 则可以。

一旦提到“最快的方式” 首先想到的是 Hash的方法 O(n) 的复杂度处理一趟就可以找出重复元素

void thesame(char *str) {

        char dsc[256] = {0};
        char *tmp;
        
        for (tmp = str; *tmp; tmp++) {
                if (dsc[*tmp] == 1) {
                        printf("%c is the same\n");
                } else {
                        dsc[*tmp] = 1;
                }
        }
} 


2)已知一随机发生器,产生0的概率是p,产生1 的概率是1-p,现在要你构造一个发生器,使得它构造0 和1的概率均为1/2;构造一个发生器,使得它构造1、2、3 的概率均为1/3;...,构造一个发生器,使得它构造1、2、3、...n 的概率均为1/n,要求复杂度最低。

分析:这道题的核心思想是,通过产生0和1的概率来组合成不同的数,代表1,2,3……n 每个数,其中产生代表每个数的概率相等。

解答:

方法一:最直观的方法,产生N位的二进制数,仅有一位为1 ,而其余位为0则符合构造数要求,否则丢弃重新选择(例如,0001 代表1, 0010 代表2,0100代表3)

这种方法显然十分低效,存在长时间选不出数的可能。

方法二:在方法一的基础上改进,既然找到了产生0 和 产生1 等概率的方法,则利用二进制表示法,可以表示出1-n中任意数

整数N 需要的位数M = log2^n+1。 则每次产生M位二进制数,其所代表的数即为所求。

3)有10个文件,每个文件1G,每个文件的每一行都存放的是用户的query,每个文件的query 都可能重复。要求按照query 的频度排序.

分析:首先应该求每个query 的频度,然后排序。最后把各部分排序好的文件合并到一起。

解答:典型的TOP K算法

方案1: 顺序读取10个文件,按照hash(query)%10的结果将query写入到另外10个文件(记为)中。这样新生成的文件每个的大小大约也1G(假设hash函数是随机的)。 找一台内存在2G左右的机器,依次对用hash_map(query, query_count)来统计每个query出现的次数。利用快速/堆/归并排序按照出现次数进行排序。将排序好的query和对应的query_cout输出到文件中。这样得到了10个排好序的文件(记为)。

   对这10个文件进行归并排序(内排序与外排序相结合)。

   方案2: 一般query的总量是有限的,只是重复的次数比较多而已,可能对于所有的query,一次性就可以加入到内存了。这样,我们就可以采用trie树/hash_map等直接来统计每个query出现的次数,然后按出现次数做快速/堆/归并排序就可以了。

   方案3: 与方案1类似,但在做完hash,分成多个文件后,可以交给多个机器来处理,采用分布式的架构来处理(比如MapReduce),最后再进行合并。

hashmap<query,query_count> 允许query为null ,先处理一趟,记下query,query_count=0; 然后再处理一趟,记录query_count++

85)又见字符串的问题

1)给出一个函数来复制两个字符串A和B。字符串A 的后几个字节和字符串B 的前几个字节重叠。

分析:

记住,这种题目往往就是考你对边界的考虑情况。

上一次解答是按照:给定 str1="abcd"; str2="cdcsd";则 res="abcdcsd";

这次解答是:写一个void * memmove(void *des, void *src ,size_t n);

         如果srcpy(B,A)这里源字符串A 的后几个字节与 目标字符串B的前几个字节重复,则从源字符串A的最后一个字节开始复制

2)已知一个字符串,比如asderwsde,寻找其中的一个子字符串比如sde 的个数,如果没有返回0,有的话返回子字符串的个数。

   

#include <cstring>
#include <iostream>
using namespace std;


int count_of_substr(const char* str, const char * sub) 
{
	int count = 0;
	const char * p = str;
	int n = strlen(sub);
	while ( *p !='\0')
	{
       if (strncmp(p, sub, n) == 0) 
	   			count ++;
		p++;

	} 
	return count;
}
int main()
{
	
	char *str1="asderwsde";
	char *str2="sde";
	
	
	cout<< count_of_substr(str1,str2)<<endl;
	
	
}

       

86)怎样编写一个程序,把一个有序整数数组放到二叉树中?

题意:建立一个中序遍历是有序的二叉树

  解答:采用递归,每次创建的节点都是 数组中间的元素 mid =length>>1 而当数组长度==0 时候,则返回NULL叶子

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
 
struct student {
        int value;
        struct student *lchild;
        struct student *rchild;
};
 
void arraytotree(int *a, int len, struct student **p) {
        if(len) {
                *p = (struct student*)malloc(sizeof(struct student));
                (*p)->value = a[len/2];
                arraytotree(a, len/2, &((*p)->lchild));
                arraytotree(a+len/2+1, len-len/2-1, &((*p)->rchild));
        } else {
                *p = NULL;
        }
}
 
void display_tree(struct student *head) {
        if(head->lchild)display_tree(head->lchild);
        printf("%d\t", head->value);
        if(head->rchild)display_tree(head->rchild);
}
 
int main() {
 
        int a[] = {1,2,3,4,9,10,33,56,78,90};
        struct student *tree;
        arraytotree(a, sizeof(a)/sizeof(a[0]), &tree);
        printf("After convert:\n");
        display_tree(tree);
        printf("\n");
        return 0;
 
}


87)三道算法题

  1)大整数数相乘的问题

    这里就是用数组模拟两个大整数相乘。

#include <iostream>
using namespace std;

void multiply(int a[],int a_length,int b[],int b_length)
{
	
	int length= a_length+b_length; 
	
	int *result=(int *)malloc(length*sizeof(int));
	
	memset(result,0,length*sizeof(int)); 
	
	int temp;//暂存两个数 
	int HF=0;//进位 
	int LF;//低位 
	
	int shift=0; 
	for(int i=b_length-1;i>=0;i--)//b[ ] 下面 
	{
		HF=0; //一趟的 进位不能进入下一趟 
		for(int j=a_length-1;j>=0;j--)//a[ ] 上面 
		{
			
			temp=b[i]*a[j]+HF;
			LF=temp%10;//取低 位  
			result[length-shift-(a_length-j)]+=LF;//低位的数加上 	
		    HF=temp/10;//取高位 
	        HF+=result[length-shift-(a_length-j)]/10; //相加产生的进位 
	        result[length-shift-(a_length-j)]%=10; //最终值 
				
		}
		shift++; 
	   result[length-shift-a_length]=HF; //最后的进位 
  	
	}
		
	for(int i=0;i<length;i++)
	{
        if(result[0] == 0)
		  continue; 
		cout<<result[i];
	} 
	cout<<endl; 
		
}

int main()
{	
	int a[]={1,2,3,4};
	int b[]={9,0,9};
	
	int length= sizeof(a)+sizeof(b); 
	int *result=(int *)malloc(  sizeof(int)  *  length );
	
    multiply(a,sizeof(a)/sizeof(int),b,sizeof(b)/sizeof(int)); 
	
	
}


  2)求最大连续递增数字串(如ads3sl456789DF3456ld345AA中的456789

#include <iostream>
using namespace std;
int continumax(char *outputstr, char *intputstr)
{
    int i, maxlen = 0;
    char * maxstr = 0;
    bool a=true;
    while (a)
    {    
        while (intputstr &&(*intputstr<'0' || *intputstr>'9')) //skip all non-digitcharacters
        {    
            intputstr++;
            if(*intputstr =='\0') 
			{
				a=false;
			    break;
			}
        }      
       int count = 0;
       char * tempstr = intputstr;
       while (intputstr &&(*intputstr>='0' && *intputstr<='9')) //OK, these characters are digits
       {    
            count++;
            intputstr++;
            if(*intputstr =='\0') 
			{
				a=false;
			    break;
			}
       }
       if (count > maxlen)
       {    
            maxlen =count;
            maxstr =tempstr;
       }     
    } 
    for (i=0; i<maxlen;i++)
    {    
       outputstr[i] = maxstr[i];
    }
    outputstr[i] = '\0';
    
    cout<<"outputstr: "<<outputstr<<endl;
    return maxlen;
}
int main()
{
	char *intputstr="abcd12345ed125ss123456789";
	
	char *outputstr=new char[100]; ;
	cout<<"cout:"<<continumax(outputstr, intputstr)<<endl;
	
	return 0;
}


  3)实现strstr功能,即在父串中寻找子串首次出现的位置

    

const char * _strstr(const char *src, const char *needle)
{
	const char *p1, *p2;
	int length_src=strlen(src);
	int length_needle=strlen(needle);
    if(length_needle > length_src)
		return NULL; 
    p1=src;
	p2=needle;		
    while(*p1!='\0')
	{
		while(*p1==*p2)
		{
			p1++;
			p2++; 
			
			if(*p2=='\0')//这里防止 到头时比较 
		    	return src; 
		    
		} 
		
		if(*p2=='\0')
		    return src; 
		else
	   {
		  p1=src+1;
		  p2=needle;	
	   } 
		src+=1; 
	} 
	
	return NULL; 
}

改进后的

char   *str_str(char   *haystack,   char   *needle) 
{ 
	char   *res=NULL; 
	int   len1=strlen(haystack); 
	int   len2=strlen(needle); 
	int   i,j,n; 

	if(len2> len1)   
		return   res; 
	n=len1-len2; 
	for(i=0;i <=n;i++) 
	{ 
		for(j=0;j <len2;j++) 
		{ 
			if(haystack[i+j]   !=   needle[j])   
				break; 
		} 
		if(j==len2) 
		{ 
			res=haystack+i; 
			break; 
		} 
	} 
	return   res; 
}



       

88)2005 年11 月金山笔试题。编码完成下面的处理函数。

  函数将字符串中的字符'*'移到串的前部分,前面的非'*'字符后移,但不能改变非'*'字符的先后顺序,函数返回串中字符'*'的数量。

  例如:原始串为:ab**cd**e*12,处理后为*****abcde12,函数并返回值为5。(要求使用尽量少的时间和辅助空间)

  思路:char *p1始终指向最后一个 ' * ',char *p2 查找p1 之前的第一个 非' * ' 然后交换,直到 p1之前没有 非' * '字符为止。由p1的位置 很容易求 字符' * '数量

解答:

int partitionStar(char a[],int length) 
{
	int i = length-1, j=length-1; // i for the cursor, j for the first non-* char
	while (i >= 0) 
	{
		if (a[i] !='*') 
			swap(a, i--, j--);
	    else
		   i--; 
	} 
	return j+1;
}

89)神州数码、华为、东软笔试题

  1)2005 年11 月15 日华为软件研发笔试题。实现一单链表的逆转。

  2)编码实现字符串转整型的函数(实现函数atoi的功能),据说是神州数码笔试题。

如将字符+123123,-0123-123,123CS45123,123.45CS123,CS123.450

int atoi(const char * a) 
{

       if (*a=='+') 
             return atoi(a+1);

       else if (*a=='-') 
	     return atoi(a+1) * (-1);

		char *p = a;

		int c = 0;

		while (*p >='0'&& *p <='9') 
		{

			c = c*10 + (*p -'0');
			p++; 
		} 
		return c;

}


  3)快速排序(东软喜欢考类似的算法填空题,又如堆排序的算法等)

  4)删除字符串中的数字并压缩字符串。如字符串abc123de4fg56处理后变为abcdefg。注意空间和效率。

   (下面的算法只需要一次遍历,不需要开辟新空间,时间复杂度为O(N)

#include <iostream>
using namespace std; 

char * partition(char *str) 
{

     int i = 0; //指向数字 
     int j = 0; //指向非数字 

     while (str[j]!='\0') 
     {

         while(str[i] > '9'|| str[i] <'0')//非数字 
              i++;
                    
         j=i; 
	     while(str[j] >'0'&& str[j] <'9')
		      j++;
			 	   
         for(int k=0;k<j-i;k++) 
		 {
		 	
	 	    swap(str[i],str[j]);
			 i++;
			 j++; 
		 }   
         
      }
      str[i] = '\0';

      return str; 

}

int main()
{
	
	char str[]="abc12454652sdjkhknnkn";  //注意这里是数组,而不能是字符串常量 
    cout<<partition(str); 
} 

  5)求两个串中的第一个最长子串(神州数码以前试题)。如"abractyeyt","dgdsaeactyey"的最大子串为"actyey"。

方法一:最基本的方法:O(n^2)

#include <iostream>
using namespace std;
const int N = 1000;

char* FirstMaxSubString(const char *str1,char *str2)
{
	int pos;  //存放第一个最长子串的起始位置
	int max = 0;  //第一个最长子串的长度
	int i,j;
	for(i=0;str1[i];i++)
	{
		for(j=0;str2[j];j++)
		{
			for(int k=0;str1[i+k]==str2[j+k] && (str1[i+k] || str2[i+k]);k++)
				if(k>max)
				{
					pos = j;
					max = k+1;
				}
		}
	}
	
	char *result = new char[max+1];
	for(i=0;i<max;i++)
		result[i] = str2[pos++];
	result[i] = '\0';
	return result;
	//或者直接用下面的语句返回,好处是不用申请空间
	/*str2[pos+max] = '/0';
	return (char *)(str2+pos);*/
}

int main()
{
	char *str1 = "abractyeyt";
	char *str2 = "dgdsaeactyey";
	
    //固定测试例
	/*
	char *str1 = "abractyeyt";
	char *str2 = "dgdsaeactyey";
	*/
	cout<<"FirstMaxSubString:"<<FirstMaxSubString(str1,str2)<<endl;
	return 0;
}

方法二:动态规划 http://blog.csdn.net/tianshuai11/article/details/7897592

90)简单三道题

  1)不开辟用于交换数据的临时空间,如何完成字符串的逆序(在技术一轮面试中,有些面试官会这样问)

  

  2)删除串中指定的字符(做此题时,千万不要开辟新空间,否则面试官可能认为你不适合做嵌入式开发)

  

  3)判断单链表中是否存在环。

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一篇 面试 ................................................................................ 8 1.1. 简介 ............................................................................................................... 8 1.2. 面试集合(一) .......................................................................................... 8 1.2.1. 把二元查找树转变成排序的双向链表.................................................... 8 1.2.2. 下排每个都是先前上排那十个在下排出现的次 ..........................11 1.2.3. 设计包含 min 函的栈 ...................................................................... 14 1.2.4. 求子数组的最大和.............................................................................. 20 1.2.5. 在二元树中找出和为某一值的所有路径 .............................................. 22 1.2.6. Top K 算法详细解析---百度面试 ......................................................... 29 1.2.7. 翻转句子中单词的顺序....................................................................... 31 1.2.8. 判断整序列是不是二元查找树的后序遍历结果 ................................ 33 1.2.9. 查找最小的 K 个元素-使用最大堆....................................................... 35 1.2.10. 求二叉树中节点的最大距离................................................................ 37 1.3. 面试集合(二) ........................................................................................ 40 1.3.1. 求 1+2+…+n....................................................................................... 40 1.3.2. 输入一个单向链表,输出该链表中倒第 k 个结点............................. 44 1.3.3. 输入一个已经按升序排序过的数组一个字.................................... 46 1.3.4. 输入一颗二元查找树,将该树转换为它的镜像.................................... 48 1.3.5. 输入一颗二元树,从上往下按层打印树的每个结点,同一层中按照从左往 右的顺序打印................................................................................................... 49 1.3.6. 在一个字符串中找到第一个只出现一次的字符。如输入 abaccdeff,则输出 b 52 1.3.7. n 个字(0,1,…,n-1)形成一个圆圈 .................................................. 53 1.3.8. 定义 Fibonacci 列 ............................................................................ 58 1.3.9. 左移递减列查找某一个.........................................

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值