[微软面试100题]41-50
第四十三题:二叉树的非递归前中后序遍历
前序遍历:
void preorderShowTreeIterative(BSTreeNode *pRoot){ stack<BSTreeNode*> buf; buf.push(pRoot); while(!buf.empty()){ BSTreeNode *p=buf.top(); buf.pop(); cout<<p->m_nValue<<endl; if(p->m_pRight!=NULL)buf.push(p->m_pRight);//right first if(p->m_pLeft!=NULL)buf.push(p->m_pLeft);//left behind } }
中序遍历:
void inorderShowTreeIterative(BSTreeNode *pRoot){ stack<BSTreeNode*> buf; BSTreeNode *current=pRoot; while(!buf.empty() || current!=NULL){ if(current!=NULL){ buf.push(current); current=current->m_pLeft;//当前不为空,则不断往左搜索 }else{ current=buf.top();//左到头了,打印中,往右搜索 buf.pop(); cout<<current->m_nValue<<endl; current=current->m_pRight; } } }
后序遍历:
void postorderShowTreeIterative(BSTreeNode *pRoot){ stack<BSTreeNode*> traverse,visit;//使用两个栈 traverse.push(pRoot); while(!traverse.empty()){ BSTreeNode *p=traverse.top(); traverse.pop(); visit.push(p);//traverse栈的顶元素进visit if(p->m_pLeft!=NULL)traverse.push(p->m_pLeft);//左右子先后进traverse if(p->m_pRight!=NULL)traverse.push(p->m_pRight); } while(!visit.empty()){//显示visit所有元素 cout<<visit.top()->m_nValue<<endl; visit.pop(); } }
第四十四题:找出重复次数最多的十条短信
1千万=10M 每条信息140char=B,总共1400MB,可以放进内存。可以用hash table计算每条信息出现的次数,然后用min heap sort来找出最多的十条。
第四十七题:求数组的最长递减子序列(非连续子序列)
思路:使用动态规划DP,存储搜索到目前为止的最长递减子序列。搜索到新的递减子序列时,先把之前的best序列中比新序列头元素要大的元素放到新序列的前面,再开始放入新序列的开头元素。如果新的序列的长度比best的长度要大,则更新。复杂度为O(n^2)
int longestDecreaseSequence(int *a,int cnt){ int bestSeq[cnt];//存放当前最长子序列 int nowSeq[cnt];//存放当前正在扫描的连续下降序列 nowSeq[0]=*a; int bLen=0,nLen=1; for(int i=1;i<cnt;++i){ if(a[i]<a[i-1]) nowSeq[nLen++]=a[i]; if(a[i]>=a[i-1] || i==cnt-1){//当序列上升时,如果now长于best则复制过去 if(nLen>bLen){ for(int j=0;j<nLen;++j) bestSeq[j]=nowSeq[j]; bLen=nLen; } if(i==cnt-1)break;//最后也必须复制一遍 nLen=0; for(int j=0;j<bLen;++j){//搜索best里面比当前新下降序列的头元素要大的元素 if(bestSeq[j]>a[i]) nowSeq[nLen++]=bestSeq[j];//放在now的前面 else break; } nowSeq[nLen++]=a[i];//最后才放入最新的元素 } } for(int i=0;i<bLen;++i)cout<<bestSeq[i]<<" "; cout<<endl; return bLen; }
网上普遍的DP方法:用一个数组记录第k个递减序列的长度和最小值。遍历到一个新元素时,搜索此元素能否加到各个递减序列中。最坏情况下复杂度为O(n^2),但使用二分查找可以把复杂度降为O(nlogn),(研究了以后发现这个算法太蛋疼就没搞了)
int tradition(int *a,int cnt){//网上传统的DP方法,只能返回最长长度.复杂度O(n^2) int len[cnt],maxLen=1;//len是第k个往后的最长降序列长度 for(int i=0;i<cnt;++i)len[i]=1; for(int i=cnt-1;i>=0;--i){ for(int j=i+1;j<cnt;++j){//从第i个开始往后搜索 if(a[i]>a[j] && len[j]>=len[i])len[i]=len[j]+1;//往后搜索过程中会不断更新i的长度 }//为了保证最后len[i]是最长的长度,只有len[j]不小于len[i]时才更新,确保len[i]不断年递增 if(len[i]>maxLen) maxLen=len[i]; } return maxLen; }
第四十七题:二分查找
int binarySearchRecur(const int *a,const int &begin,const int &end,const int &t,int ascend=1){//1 is ascend , 0 is descend if(a==NULL)return -1;//defense programming; use const & to save memory if(begin==end)return begin; if((1==ascend && a[begin+(end-begin)/2]>=t) || (0==ascend && a[begin+(end-begin)/2]<=t)){ return binarySearchRecur(a,begin,begin+(end-begin)/2,t,ascend); }else{ return binarySearchRecur(a,begin+(end-begin)/2+1,end,t,ascend);//begin+end may overflow } } int binarySearch(const int *a,const int &begin,const int &end,const int &t,int ascend=1){ int b=begin,e=end,m=begin+(end-begin)/2; if(a==NULL)return -1;//defense programming; use const & to save memory while(b<=e){ if(b==e)break; if((1==ascend && a[m]>=t) || (0==ascend && a[m]<=t)) e=m; else b=m+1; m=b+(e-b)/2; } return b; }
第四十八题:二分查找左移递减数列
思路:一个左移的递减序列从中点分割成两份后,一定是一份是纯递减数列,一列也是左移递减数列。
判断哪边是纯递减是看中间元素是否小于头元素。 如果要找的目标在纯递减则使用二分,否则递归自身。
int shiftedBinarySearch(int *a,int begin,int end,int t){ const int b=begin,e=end,m=begin+(end-begin)/2; if(a==NULL)return -1;//defense programming; use const & to save memory while(b<=e){ if(b==e)break; if(a[m]<=a[begin] && a[begin]>=t && a[m]<=t) return binarySearch(a,b,m,t,0); else if(a[m]<=a[begin]) return shiftedBinarySearch(a,m+1,e,t); else if(a[m]>=a[begin] && a[end]<= t && a[m+1]>=t) return binarySearch(a,m+1,e,t,0); else return shiftedBinarySearch(a,b,m,t); } return b; }