面试题学习

参考:http://blog.csdn.net/v_july_v/article/details/7974418

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

 

   建立一张用户信息表usermonth,存放30天的user_id

   select  count(*) from user u inner join usermonth um on u.user_id=um.user_id;

   和select count(*) from from user u,usermonth um where u.user_id=um.user_id

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

下面的思路是为每个字母一个素数对应,按乘积来进行hash计算。估计有乘法溢出问题,此处没有考虑.

unsigned  primes[26];
map<unsigned,vector<string> > values;
bool isprime(int t){
	for(int i=2;i<=sqrt(t+0.0);++i){
	  if(t%i==0) return false; 
	}
	return true;
}
void init(){
    int a=2,i=0;
	for(int j=2;;j++){
		if(isprime(j)){
		  primes[i++]=j;
		}
		if(i==26) break;
	}
}
unsigned getval(const string & s){
	unsigned val=1;
   for(size_t j=0;j<s.size();++j){
	    val*=primes[s[j]-'a'];
	  }
   return val;
}
int main(){
  init();
  string s[]={"army","yarm","amry","hello","helol","olleh"};
  for(int i=0;i<6;++i){
	  values[getval(s[i])].push_back(s[i]);
  }
  string search="army";
  unsigned v=getval(search);
  if(values.count(v)==1){
     for(size_t i=0;i<values[v].size();++i)
		 cout<<values[v][i]<<endl;
  }
  system("pause");
 return 0;
}
 

三:百度搜索框的suggestion,比如输入“北京”,搜索框下面会以北京为前缀,展示“北京爱情故事”、“北京公交”、“北京医院”等等搜索词,输入“结构之”,会提示“ 结构之法”,“结构之法 算法之道”等搜索词。

请问,如何设计此系统,使得空间和时间复杂度尽量低。

----利用trie树进行单词的统计,然后top k查询出出现频率高的单词显示


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

  1. //{1,2,3,4,5,6,7,8,9,10}   1  
  2. //{4,5,6,7,8,9,10,1,2,3}   1  
  3. //{1,1,1,1,1,1,1,1,1,1}    1  
  4. //{1,9,10,1,1,1,1,1,1,1}   1  
  5. //{9,9,9,9,9,9,9,10,1,9}

int findMin(const int* arr,int left,int right){
    if(arr[left]<arr[right])//no rotate
    return arr[left];
    int low=left,high=right;
   while(low<high){
       int mid=low+((high-low)>>1);
       if(arr[mid]>=arr[left]) low=mid+1;
       else if(arr[mid]<=arr[right]) high=mid-1;
       if(mid>0&&arr[mid]<arr[mid-1]) return arr[mid];
   }
   return min(arr[low],arr[high]);
}
int main(int argc, char** argv) {
    int arr[]={4,5,6,7,8,9,10,1,2,3};
    cout<<findMin(arr,0,sizeof(arr)/sizeof(int)-1);
    return 0;
}

五:找出两个单链表里交叉的第一个元素

方法一:分别遍历list1、list2,计算得到L1,L2;

比较最后结点是否相等,相等则表明是两个链表是交叉的

如果交叉:长的链表先移动|L1-L2|步,再逐个比较,等到第一个交点!

方法二:利用hash的思想


六:字符串移动(字符串为*号和26个字母的任意组合,把*号都移动到最左侧,把字母移到最右侧并保持相对顺序不变),要求时间和空间复杂度最小

void trans(char* str){
   int len=strlen(str);
    int i=len-1,j=len-1;
    while(j>=0){
      while(str[j]=='*') j--;
      str[i--]=str[j--];
    }
   for(j=0;j<=i;++j)
     str[j]='*';
  
}
int main(int argc, char** argv) {
   char str[]="abcd**def*gh";
   trans(str);
   cout<<str<<endl;
    return 0;
}

七: 平面上有很多点,点与点之间有可能有连线,求这个图里环的数目
对于图上的每个点,标记三种状态:A:未找到经过该点的环,B:已经找到经过该点的环,C:未访问到该点,D:该点访问过1次,E:该点访问过2次或以上。
初始情况,每个点都是A以及C状态。
首先,以某个点如v1为起点进行宽度优先遍历,当访问到任意一点如v2有以下三种情况:
1.若v2状态未C,则v2状态改为D;
2.若v2状态为D,状态改为E,把v1状态变为B,v1经过的环数加1,同时访问到v2的这条路线终止
3.若v2状态为E,访问到v2的这条路线终止。
遍历完,则找到所有v1参与的环的数目。这个过程为O(n)。
然后,则以另一个点如v3为起点,遍历整张图,这时需要把先每个点状态恢复为C。这里遍历就要加一个限制,若访问到状态为B的点,这条路线终止,因为状态为B的点参与的所有环已经在前面的步骤中找到。这样就可以找到v3参与的但与前面的环不重复的环的数目。


8. 阿里:搜索引擎中5忆个url怎么高效存储?


   采用B+树,分布式存储


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

struct Rect{
  Rect(double _lbx,double _lby,double _rux,double _ruy):lbx(_lbx),lby(_lby),rux(_rux),ruy(_ruy){}
  double lbx;
  double lby;
  double rux;
  double ruy;
};
inline double Min(double a,double b){
  return a>b?b:a;
}
inline double Max(double a,double b){
  return a>b?a:b;
}
double getInter(const Rect& a,const Rect& b){
  //get the inter area ....else return -1
  double dx=Min(a.rux,b.rux)-Max(a.lbx,b.lbx);
  double dy=Max(a.ruy,b.ruy)-Max(a.lby,b.lby);
  return  dx>=0&&dy>=0?dx*dy:-1;
}


10.计算一个整数的幂

int pow2(int a,int n){
  int ret=1;
  while(n>0){
    if(n&1){
      ret*=a;
    }
     a*=a;
    n>>=1;
  }
  return ret;
}


11逆转一个字符串递归调用

#include <stdio.h>
#include <string.h>
char  * Reverse (char *s)  
{  
 if(strlen(s) == 1)
       return s;
 if(*(s))  
 {  
  int len = strlen(s);
  *(s+len) =  *s;   
  *s   =  *(s+len-1);
  *(s+len-1) = '\0';
  //首尾字符及结束符交换位置

  Reverse (s+1); //去掉首尾字符后再递归调用
  
  *(s+len-1) = *(s+len);
  *(s+len) = '\0'; // 恢复原来改变后的串,这里也会递归的恢复
 }  
 return s;  
}

void main()
{
 char from[] = "abcd";
 printf("%s\n",Reverse(from));
}


第三十四~三十五章:格子取数,完美洗牌算法

链接地址:http://blog.csdn.net/v_july_v/article/details/10212493

题目详情:有n*n个格子,每个格子里有正数或者0,从最左上角往最右下角走,只能向下和向右,一共走两次(即从左上角走到右下角走两趟),把所有经过的格子的数加起来,求最大值SUM,且两次如果经过同一个格子,则最后总和SUM中该格子的计数只加一次。

题目详情:有个长度为2n的数组{a1,a2,a3,...,an,b1,b2,b3,...,bn},希望排序后{a1,b1,a2,b2,....,an,bn},请考虑有无时间复杂度o(n),空间复杂度0(1)的解法。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值