参考:http://blog.youkuaiyun.com/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,2,3,4,5,6,7,8,9,10} 1
- //{4,5,6,7,8,9,10,1,2,3} 1
- //{1,1,1,1,1,1,1,1,1,1} 1
- //{1,9,10,1,1,1,1,1,1,1} 1
- //{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.youkuaiyun.com/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)的解法。