声明:本文资料来自于 牛客网(算法初级笔记2)
/* 题目1: 给定一个数组arr,和一个数num,请把小于等于num的数放在数 组的左边,大于num的数放在数组的右边。 思路:两个指针,一个less,一个cur,碰到大于num的,cur指针前移,less不动 碰到小于等于num的,less的下一个指针和cur交换,less和cur 都 自增 1 */ class niukeClass_1 { void swap(vector<int>arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } vector<int> partition(vector<int>&arr,int num){ if(arr.size()==0)return arr; int less = -1; int cur=arr[0]; while (cur<arr.size()) { if(arr[cur]<=num){ swap(arr, ++less, cur++); } else { cur++; } } return arr; } }; /* 题目二 :荷兰国旗 给定一个数组arr,和一个数num,请把小于num的数放在数组的 左边, 等于num的数放在数组的中间,大于num的数放在数组的 右边。 要求额外空间复杂度O(1),时间复杂度O(N) 思路: 1 设置一个起始位置的左边的一个变量less,用于记录小于num的范围坐标 2 设置一个最大位置的右边的一个变量more,用于记录大于num的范围坐标 3 设置一个当前的指针,用于遍历当前数组的值 4如果当前cur的值小于p,当前位置和less的下一个值交换,然后less++,cur++ 5如果当前的cur的值大于p,当前位置和more的上一个位置交换,然后交换之后的cur继续执行步骤4 6 如果当前的cur的值等于p,cur++ */ class niukeClass_2 { void swap(vector<int>&arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } /* 参数1:数组 参数2:数组的左边界 参数3:数组的右边界 参数4:num 返回值: 等于p的左边界坐标和右边界坐标 */ vector<int> partition(vector<int>&arr,int l,int r,int p){ int less = l-1; int more = r+1; int cur = l; while (cur<more) { if(arr[cur]<p){ swap(arr, ++less, cur++); } else if(arr[cur]>p){ swap(arr,--more,cur);//cur不加的原因是,还要走上一个if } else { cur++; } } vector<int>vec; vec.push_back(less+1); vec.push_back(more-1); return vec; } }; /* 题目三: 随机快速排序 经典快排缺点: 1 以数组最后一个元素num为参照,小于等于num的放左边,大于num的放右边,每次只能确定一个位置 2 [654321]的数组,以1开始,这样每次分的右边为空,时间复杂度为O(n^2) 改进: 1 用 随机坐标作为 num,这样快排的最坏时间复杂度就是概率问题了,平均为 O(NlogN) 2 用荷兰国旗问题改进快排,每次排完之后,中间为所有等于num的数,这样 这些数就不用在对比了,常数计算快一些 问题:快排的额外空间复杂度 logN 原因: 每二分一次,都需要记录中间的断点位置,这样弄完左边之后,才能根据断点找到右边继续递归,也就是说每二分一次,就需要一个断点,那么 总共二分了logN,所以额外空间负责度为O(logN) 但是如果类似于 1234567,断点第一次打在7,第二次6。。,这样空间负责度就会变为 O(n),所以最快情况下为O(n) 这也是个概率问题,长期期望值 为 O(logN) */ class niuheclass_3{ public: void swap(vector<int>&arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } //9 6 12 16 7 20 5 1 vector<int> partition(vector<int>&arr,int l,int r){ int less = l-1; int more = r+1; int cur = l; int p = arr[r];//把最后一个值作为分界值 while (cur<more) { if(arr[cur]<p){ swap(arr, ++less, cur++); } else if(arr[cur]>p){ swap(arr,--more,cur);//cur不加的原因是,还要走上一个if } else { cur++; } } vector<int>vec; vec.push_back(less+1); vec.push_back(more-1); return vec; } void quickSortSub(vector<int>&arr,int l ,int r){ if(l<r){ //选中随机的坐标,然后和最后一个坐标交换 int randomPosition =l+(int)( (rand() % (999 + 1) / (float)(999 + 1)) * (r-l+1)); swap(arr,randomPosition,r); vector<int>vec = partition(arr, l, r); quickSortSub(arr, l, vec[0]-1); quickSortSub(arr, vec[1]+1, r); } } void quickSort(vector<int>&arr){ if(arr.size()<2){ return; } quickSortSub(arr, 0, (int)arr.size()-1); } }; /* 题目三:建立大根堆的过程 问题: 建立大顶堆的时间复杂度 答案: 每一个节点插进来的时候都与已经形成的二叉树的高度有关,有n个节点,高度就为logN 第一个节点插件来就是log1,第二个节点就是log2.。。 第n-1个节点就是logn-1 所以 log1 + log2 +。。。+logN-1 = O(N) */ class niukeClass_3 { void swap(vector<int>&arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } /* 参数1:数组 参数2:数组的第几个元素 思路: 每次插入的时候,和他的父节点进行比较,如果大于父节点,和父节点交换为孩子, 然后父节点接着和父节点的父节点比较,直到小于等于为止(顶点元素是相等的,所以条件会终止) 父节点的位置 = (当前节点的位置-1)/ 2 */ void heapInsert(vector<int>arr,int index){ while (arr[index]>arr[(index-1)/2]) { swap(arr, index, (index-1)/2); index = (index-1)/2; } } }; /* 题目4: 调整大顶堆中某一个元素 思路: 当修改大顶堆中某一个位置的元素的时候,该元素a和他的左右子树中较大的值b比较,如果a<b,a和b互换位置,然后继续向下比较 如果 a的值不大于b,跳出循环 */ class niukeclass_4{ void swap(vector<int>&arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } /* 参数1:构成大顶堆的数组 参数2:调整的元素的坐标 参数3:大顶堆的元素个数 */ void heapify(vector<int>arr,int index,int size){ int left = index*2+1; while (left<size) { //如果右子树没有越界并且大于左子树,最大值就是右子树,否则左子树 int largest = (left+1)<size && arr[left+1]>arr[left]?left+1:left; largest = arr[largest]>arr[index]?largest:index; if(largest == index){ break; } swap(arr, largest,index); index = largest; left = index*2 + 1; } } }; /* 题目5 实现堆排序 思路: 1 根据数组建立大根堆 2 每次最后一个元素和 第一个元素交换,最后一个元素就是最大值, 然后把除了最后一个元素以外的大顶堆重新调整为大根堆 3 直到所有元素全部调整完毕 */ class class_heapSort { /* 入口方法 */ public: void heapSort(vector<int>&arr){ if(arr.size()<2){ return; } for (int i = 0; i < arr.size(); i++) { heapInsert(arr, i); } int size = (int)arr.size(); swap(arr,0,--size); while (size>0) { heapify(arr, 0, size);//每次调整的时间复杂度为logN,效率高 //继续交换第一个和最后一个元素 swap(arr, 0, --size); } } private: void swap(vector<int>&arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } void heapify(vector<int>&arr,int index,int size){ int left = index*2+1; while (left<size) { //如果右子树没有越界并且大于左子树,最大值就是右子树,否则左子树 int largest = (left+1)<size && arr[left+1]>arr[left]?left+1:left; largest = arr[largest]>arr[index]?largest:index; if(largest == index){ break; } swap(arr, largest,index); index = largest; left = index*2 + 1; } } void heapInsert(vector<int>&arr,int index){ while (arr[index]>arr[(index-1)/2]) { swap(arr, index, (index-1)/2); index = (index-1)/2; } } };