一、二叉排序树第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;
思路:中序遍历
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、读取每个小文件,建立哈希表