[微软面试100题]81-90
第八十一题:
1、求数组中大于左边所有元素,小于右边素有元素的数。只能用一个额外数组。
思路:从左往右遍历先把max记录在额外数组中。从右往左遍历记录当前min在一个变量中。对比min和max和当前即可。
//复杂度O(n),2次迭代,使用1个数组 void helper(int *a,int n){ int nowmax=a[0],nowmin=a[n-1]; int max[n]; for(int i=0;i<n;++i){ if(a[i]>nowmax)nowmax=a[i]; max[i]=nowmax; } for(int i=n-1;i>=0;--i){ if(a[i]<nowmin)nowmin=a[i]; if(a[i]>=max[i] && a[i]<=nowmin)cout<<a[i]<<endl; } }
2、一千万条字符串,找出所有系相反的字符串。
思路:先hash所有字符串,然后一条一条翻转再hash,冲突则输出即可。
第八十二题:
1、用C++模拟类似SQL的存储以及查询功能
class col { public: string name; int age; int index; static int nowindex; col(string name,int age); }; int col::nowindex=0;//静态成员类外初始化 class table { vector<col> cols;//用序号对vector随机存取 map<string,int> name2index;//用一个hashtable关联名字和序号 public: void insert(string name,int age); int find_age(string name); void find_name(char c,int age); }; col::col(string name,int age){ index=nowindex; nowindex++; this->name=name; this->age=age; } void table::insert(string name,int age){ col tmp(name,age); cols.push_back(tmp); name2index[name]=tmp.index; } int table::find_age(string name){ if(name2index.find(name)!=name2index.end()){//判断map元素是否存在方法 int index=name2index[name]; return cols[index].age; } return -1; } void table::find_name(char c,int age){ int len=cols.size(); bool has_result=false; if(c=='='){ for(int i=0;i<len;++i) if(cols[i].age==age){ has_result=true; cout<<cols[i].name<<endl; } }else if(c=='>'){ for(int i=0;i<len;++i) if(cols[i].age>age){ has_result=true; cout<<cols[i].name<<endl; } }else if(c=='<'){ for(int i=0;i<len;++i) if(cols[i].age<age){ has_result=true; cout<<cols[i].name<<endl; } }else cout<<"error"<<endl; if(!has_result)cout<<"not found"<<endl; }
2、100亿条记录,包括两个字段{URL,SIZE},用shell抓取出包含baidu的size,并根据size排名
shell以后再复习。。。忘记了。。
思路:如果是C++的话,先找出含有baidu的,然后用堆排序。
第八十三题:实现memcpy函数
PS:注意区间重叠的情况即可
void* memmove(void* dest,const void* src,size_t n){ if(dest==NULL || src==NULL)return NULL; char* byte_src=(char*)src; char* byte_dest=(char*)dest; int step=1; if((size_t)dest<(size_t)src+n){//防止原内存区间与目标区间重叠 byte_src+=n-1; byte_dest+=n-1; step=-1; }//目标区间比原区间后,则需从最后开始复制 //虽然重叠但目标在原区间前,则不会冲突 for(size_t i=0;i<n;++i){ *byte_dest=*byte_src; byte_dest+=step; byte_src+=step; } return dest; }
第八十四题:
1、用最快的方法找出相同的字符串
思路:(1)hash(2)字典树
2、字符串中子串的个数
思路:(1)从左往右扫不断对比,复杂度O(mn);(2)从左往右的hash,复杂度O(m)
第八十六题:二叉树存放有序数组
思路:死记硬背不好,只要那个1到7的数组写出它的前序、中序、后序遍历二叉树就知道程序怎么写了。
//前序遍历顺序。根节点是第一个元素,后面的元素分开两半,分别递归即可。 void BinaryTreeNode::buildfirst(int *a,int n){ this->m_nValue=a[0]; int lenleft=(n-1)/2; if(lenleft>0){ this->m_pLeft=new BinaryTreeNode; this->m_pLeft->buildfirst(a+1,lenleft); } if(n-1-lenleft>0){ this->m_pRight=new BinaryTreeNode; this->m_pRight->buildmid(a+1+lenleft,n-lenleft-1); } }
//中序遍历顺序。根节点是中间元素,前后两段元素分别递归即可。 void BinaryTreeNode::buildmid(int *a,int n){ int mid=n/2; this->m_nValue=a[mid]; if(mid>0){ this->m_pLeft=new BinaryTreeNode; this->m_pLeft->buildmid(a,mid); } if(n-mid-1>0){ this->m_pRight=new BinaryTreeNode; this->m_pRight->buildmid(a+mid+1,n-mid-1); } }
//后序遍历顺序。根节点是最后一个元素,前面的元素分开两半,分别递归即可。 void BinaryTreeNode::buildlast(int *a,int n){ this->m_nValue=a[n-1]; int lenleft=(n-1)/2; if(lenleft>0){ this->m_pLeft=new BinaryTreeNode; this->m_pLeft->buildlast(a,lenleft); } if(n-1-lenleft>0){ this->m_pRight=new BinaryTreeNode; this->m_pRight->buildlast(a+lenleft,n-lenleft-1); } }
第八十七题:大数相乘
思路:用字符串逐位相乘,累加到结果的数组中。最后处理结果数组考虑进位。
string muti(string s1,string s2){ int len1=s1.length(),len2=s2.length(); int *i1=new int[len1]; int *i2=new int[len2]; int *result=new int[len2+len1]; memset(result,0,(len1+len2)*sizeof(int)); for(int i=0;i<len1;++i) i1[i]=s1[len1-i-1]-'0'; for(int i=0;i<len2;++i) i2[i]=s2[len2-i-1]-'0'; for(int i=0;i<len1;i++){ for(int j=0;j<len2;j++) result[i+j]+=i1[i]*i2[j]; } for(int i=0;i<len1+len2;++i){ if(result[i]>9){ result[i+1]+=result[i]/10; result[i]=result[i]%10; } } string str; bool flag=true; for(int i=len1+len2-1;i>=0;--i){ if(flag && result[i]==0)continue; flag=false; str+=result[i]+'0'; } delete [] i1; delete [] i2; delete [] result; return str; }
大数相加:
string add(string s1,string s2){ int len1=s1.length(),len2=s2.length(); int *i1=new int[len1]; int *i2=new int[len2]; int len3=len1>len2?len1+1:len2+1; int *result=new int[len3]; memset(result,0,len3*sizeof(int)); for(int i=0;i<len1;++i) i1[i]=s1[len1-i-1]-'0'; for(int i=0;i<len2;++i) i2[i]=s2[len2-i-1]-'0'; for(int i=0;i<len3-1;i++){ if(len1<len2 && i>=len1) result[i]=i2[i]; else if(len2<len1 && i>=len2) result[i]=i1[i]; else result[i]=i1[i]+i2[i]; }for(int i=0;i<len3;++i){ if(result[i]>9){ result[i+1]+=result[i]/10; result[i]=result[i]%10; } }
string str; bool flag=true; for(int i=len3-1;i>=0;--i){ if(flag && result[i]==0)continue; flag=false; str+=result[i]+'0'; } delete [] i1; delete [] i2; delete [] result; return str; }
第八十八题:把*移到字符串前部
思路:记录两个坐标,一个是最后一个星,一个是最后一个字母。从后往前扫,扫到字母就与最后一个星交换。
int helper(char *s){ int len=strlen(s); int i=len-1,j=len-1,count=0; while(j>=0){//j往前扫,直到不是*,i的位置一定是最后一个* if(s[j]!='*'){ swap(s,i--,j--);//交换了以后,i-1肯定是* //如2个*连续则交换后显然是*;只有1个*的话,下一个就是刚交换的* }else{ count++; j--; } } return count; }
第八十九题:删除字符串中的数字
思路:与上题基本一致。while循环一次做cursor移动一步,不要再用while,否则代码不简洁。
bool is_digit(char c){ return (c>='0' && c<='9')?true:false; } char* helper(char *s){ int i=0,j=0; while(s[j]!='\0'){ if(!is_digit(s[j]))s[i++]=s[j++]; else j++; } s[i]='\0'; return s;
第九十题:不使用临时空间翻转字符串
//模拟一个栈,如果只是翻转输出的话 void helper(char *s,int i,int n){ if(i<n-1){ helper(s,i+1,n);//没到最后,先递归 cout<<s[i]<<endl;//递归完说明此元素之后的元素已经处理完毕,可处理此元素了 } else cout<<s[i]<<endl;//最后的元素,停止递归 } void helper2(char *s,int n){ int i=0,j=n-1; while(j>i){ char tmp=s[i]; s[i]=s[j]; s[j]=tmp; ++i; --j; } }
//如何真的连一个char都不能申请只能使用 //想起一种不借助临时变量交换变量的方法 void helper3(char *s,int n){ int i=0,j=n-1; while(j>i){ s[i]^=s[j];//左包含ij的与或 s[j]^=s[i];//右包含jij=i s[i++]^=s[j--];//左包含iji=j } }