算法面试题

一、二叉排序树第k个最小值
思路:中序遍历
kthSmallest(Node* root, int& k, Node* res){
if(k<=0 || root == NULL){
return;
}
kthSmallest(root->left,k,res);
if(k<=0){
return;
}
k--;
if(k==0){
res = root;
return;
}
kthSmallest(root->rigth,k,res);
}


二、二叉排序树第k个最大值
思路:右子树=>根结点=>左子树
kthBiggest(Node* root, int& k, Node* res){
if(k<=0 || root == NULL){
return;
}
kthSmallest(root->right,k,res);
if(k<=0){
return;
}
k--;
if(k==0){
res = root;
return;
}
kthSmallest(root->left,k,res);
}


三、二叉排序树
struct TreeNode  
{  
    int val;  
    TreeNode *left;  
    TreeNode *right;  
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}  
};  
1、生成
递归版:
bool BSTInsert(TreeNode* &root,int val){
if(root == NULL){
root = new TreeNode(val);;
return true;
}
if(val == root.val){
return false;
}else if(val < root.val){
return  BSTInsert(root->left,val);
}else{
return BSTInsert(root->right,val);
}
}
void BSTCreate(TreeNode* &root,vector<int> &a)  
{  
    for (int val : a)  
        BSTInsert(root, val);  
}  


四、堆排序
//调整大顶堆
adjustHeap(int[] arr, int i, int length){
int temp = arr[i]; //取出当前元素
for(k=2*i+1;k<length;k=k*2+1){ //
if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
k++;
}
if(arr[k]>temp){ //如果子节点大于父节点,将子节点值赋给父节点
arr[i]=arr[k];
i=k;
}else{
break;
}
}
arr[i]=temp;
}


heapSort(int[] arr){
//构建大顶堆
for(int i=arr.length/2-1;i>=0;i--){
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
for(int j=arr.length-1;j>0;j--){
swap(arr[j],arr[0]); //将堆顶元素与末尾元素进行交换
adjustHeap(arr,0,j); //重新对堆进行调整
}
}


五、100亿个数字找出最大的10个
1、建立小顶堆
2、分块处理,然后再合并。如分100个块,每个块1亿个数字,每块找出最大10个数,然后两块两块合并找出最大10个数。
3、快速排序:分区时,根据数P将数组分为两部分,设大于P的数个数为a,小于P的数的个数为b。
如果,a>=10,则从这a个数取最大的k个数,若a<10,则从b个数取最大的10-a-1个。


六、快速排序
quickSort(int[] arr,int startIndex,int endIndex){
if(startIndex>=endIndex){
return;
}
int temp = arr[startIndex];
int leftIndex = startIndex;
int rightIndex = endIndex;
while(leftIndex < rightIndex){
while(leftIndex < rightIndex && arr[rightIndex] >= temp){
rightIndex--;
}
arr[leftIndex] = arr[rightIndex];
while(leftIndex < rightIndex && arr[leftIndex] <= temp){
leftIndex++;
}
arr[rightIndex] = arr[leftIndex];

}
arr[leftIndex] = temp;
quickSort(arr,startIndex,leftIndex-1);
quickSort(arr,rightIndex+1,endIndex);
}


七、链表
struct ListNode
{
    int key;
    ListNode * next;
};
1、判断一个单链表是否有环
思路:快慢指针,每次慢指针走一步,快指针走两步
Node* isCricleList(Node* head){
Node* fast = head;
Node* slow = head;
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
if(slow == fast){
return slow;
}
}
return NULL;
}
2、如果单链表有环,找出环的入口节点
思路:先求出相遇结点m,头结点p和m同步前进,最后p与m相遇的地方就是环入口结点
证明:假设头结点为h,环入口结点为t,相遇结点为m,h与t的矩离为a,从t走到m的矩离为x,环的周长为l;
相遇时慢指针走了s,则快指针走了2s,则
s=a+x; //快慢指针相遇时,慢指针不会走满一环
2s=a+x+nl; //n表示快指针已经走了n环
=> a+x=nl;
=> a=nl-x;
=>假设指针p1从头走,指针p2从结点m走;当p1走到t时,走了a,则p2走了nl-x,由于p2是从结点m开始走的,结点m与结点t的矩
离为x,则nl-x即是结点t处;因此p1与p2在结点t处相遇,即p1与p2相遇的结点就是环入口结点。


Node* findEntranceNode(Node* head){
Node* meetNode = isCricleList(head);
Node* p = head;
while(p != meetNode){
p = p->next;
meetNode = meetNode->next;
}
return p;
}
3、求环的长度
int circleLength(Node* head){
Node* meetNode = isCricleList(head);
node* p = meetNode->next;
int len = 1;
while(p != meetNode){
len++;
p = p->next;
}
return len;
}
4、已知单链表头结点,查找倒数第k个结点
思路:快慢指针,先让一个指针走到第k个结点,然后两个指针再同时走,快指针走到最后时,慢指针对应的结点就是解
5、已知链表头结点,查找链表的中间结点
思路:快慢指针,快指针每次走两步,慢指针每次走一步,最后慢指针所在结点就是解


八、两个栈实现一个队列
栈a作为入队,入队时直接压到栈a;
栈b作为出队,出队时:1、如果栈b不为空,则直接出栈;2、如果栈b为空,则先将栈a的全部元素移到栈b,再出栈。


九、在一组排序数中,给定一个数,返回最接近且不大于这个数的位置,要求时间在O(logn) 
思路:用二分查找,low和high相差为1时,low即为所求结果的下标。
int BSearch(int[] num, int key) {
    if(key>=num[num.length-1]){
        return num[num.length-1];
    }
    int low = 0;
    int high = num.length - 1;
    int mid;
    while (low <= high) {
        if (high - low <= 1)
            break;
        mid = (high + low) / 2;
        if (num[mid] > key) {
            high = mid;
        } else {
            low = mid;
        }
    }
    return num[low];
}


十、单链表反序
Node* reverseList(Node* head){
Node* newHead = NULL;
Node* temp = NULL;
while(head != NULL){
temp = head;
head = head->next;
temp->next = newHead;
newHead = temp;
}
return newHead;

}


十一、给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url
分治算法的思想
1、遍历文件a,对每个url求取hash(url)%1000,然后根据所取得的值将url分别存储到1000个小文件
2、遍历文件b,采取和a相同的方式将url分别存储到1000个小文件
3、读取每个小文件,建立哈希表

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值