程序员面试题总结一:排序算法
来源:互联网 发布:chrome mac版 编辑:程序博客网 时间:2024/05/16 19:23
关于排序算法的详细介绍网上很多,本人不再赘述,因为本文讲的是常见的面试题。
如果还有同学不是很了解排序相关算法原理,请参考如下博客:排序算法经典详解
本文章源代码请参考:GitHub上源代码参考
推荐一个刷题网站LeetCode 和一个相关博客LeetCode题解
排序算法常见面试题:
面试题1:手写快速排序代码
基本思想:快速排序算法的基本思想为分治思想。
- 先从数列中取出一个数作为基准数;
- 根据基准数将数列进行分区,小于基准数的放左边,大于基准数的放右边;
- 重复分区操作,知道各区间只有一个数为止。
算法流程:(递归+挖坑填数)
- i=L,j=R,将基准数挖出形成第一个坑a[i];
- j--由后向前找出比它小的数,找到后挖出此数a[j]填到前一个坑a[i]中;
- i++从前向后找出比它大的数,找到后也挖出此数填到前一个坑a[j]中;
- 再重复2,3),直到i=j,将基准数填到a[i]。
时间复杂度:O(nlog(n)),但若初始数列基本有序时,快排序反而退化为冒泡排序。
C++源代码实现:
class Solution {public: int Partition1(vector<int>& nums, int low, int high){ int key = nums[low]; while(low < high){ while(low < high && nums[high] >= key) high--; swap(nums[low], nums[high]); while(low < high && nums[low] <= key) low++; swap(nums[low], nums[high]); } return low; } int Partition2(vector<int>& nums, int low, int high){ int pos = low; for(int i = low; i < high; i++){ if(nums[i] <= nums[high]) swap(nums[pos++], nums[i]); } swap(nums[pos++], nums[high]); return pos - 1; } int QuickSort(vector<int>& nums, int low, int high){ if(low < high){ int index = Partition2(nums, low, high); QuickSort(nums, low, index - 1); QuickSort(nums, index + 1, high); } } void sortIntegers(vector<int>& nums) { QuickSort(nums, 0, (int)nums.size() - 1); }};
面试题2:手写堆排序代码
基本思想:
- 初始时把要排序的n个数的序列看作是一棵顺序存储的二叉树(一维数组存储二叉树),调整它们的存储序,使之成为一个堆,将堆顶元素输出,得到n 个元素中最小(或最大)的元素,这时堆的根节点的数最小(或者最大)。
- 然后对前面(n-1)个元素重新调整使之成为堆,输出堆顶元素,得到n 个元素中次小(或次大)的元素。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。称这个过程为堆排序。
- 因此,实现堆排序需解决两个问题:
1. 如何将n 个待排序的数建成堆?
2. 输出堆顶元素后,怎样调整剩余n-1 个元素,使其成为一个新堆?
时间复杂度分析:O(nlog(n)),堆排序是一种不稳定的排序算法。
C++源代码实现:
class Solution {public: void MaxHeap(vector<int>& nums, int parent, int len){ int child = 2 * parent + 1; while(child < len){ while(child + 1 < len && nums[child] < nums[child + 1]) child++; if(nums[child] > nums[parent]){ swap(nums[child], nums[parent]); parent = child; child = 2 * parent + 1; }else break; } } void HeapSort(vector<int>& nums){ int len = nums.size(); for(int i = (len - 1)/2; i >= 0; i--) MaxHeap(nums, i, len); for(int j = len ; j > 0; j--){ MaxHeap(nums, 0, j); swap(nums[0], nums[j - 1]); } } void sortIntegers(vector<int>& nums) { HeapSort(nums); }};
面试题3:手写归并排序代码
基本思想:
- 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。
- 然后再把有序子序列合并为整体有序序列。
算法流程:(迭代+两个有序数列合并为一个有序数列)
时间复杂度:O(nlog(n)),归并算法是一种稳定排序算法。
C++源代码实现:
class Solution {public: void MergeArray(vector<int>& nums, int low, int high){ vector<int> temp(high - low + 1, 0); int mid = (low + high)/2, k = 0; int i = low, m = mid, j = mid + 1, n = high; while(i <= m && j <= n){ if(nums[i] <= nums[j]) temp[k++] = nums[i++]; else temp[k++] = nums[j++]; } while(i <= m) temp[k++] = nums[i++]; while(j <= n) temp[k++] = nums[j++]; for(int p = 0; p < temp.size(); p++) nums[low + p] = temp[p]; } void MergeSort(vector<int>& nums, int low, int high){ if(low < high){ int mid = (low + high)/2; MergeSort(nums, low, mid); MergeSort(nums, mid + 1, high); MergeArray(nums, low, high); } } void sortIntegers(vector<int>& nums) { MergeSort(nums, 0, (int)nums.size() -1); }};
题源:[Leetcode 75] Sort Colors颜色排序
题意:数组内有n个0,1,2,进行排序,使其按照0,1,2的顺序,即,红,白,蓝的顺序。
题解:题目中还要让只遍历一次数组来求解,那么我需要用双指针来做,分别从原数组的首尾往中心移动。
定义left指针指向开头位置,right指针指向末尾位置,从头开始遍历原数组,
如果遇到0,则交换该值和left指针指向的值,并将left指针后移一位。
若遇到2,则交换该值和right指针指向的值,并将right指针前移一位。若遇到1,则继续遍历。
源代码:
class Solution {public: void sortColors(vector<int>& nums) { int left = 0, i = 0, right = nums.size() - 1; while( i <= right){ if(nums[i] == 0) swap(nums[i++], nums[left++]); else if(nums[i] == 1) i++; else swap(nums[i], nums[right--]); } }};
题源:[Leetcode 179] Largest Number最大组合数
题意:一个数组,让我们将其拼接成最大的数
题解:根据题目中给的例子来看,主要就是要给给定数组进行排序,但是排序方法不是普通的升序或者降序,
因为9要排在最前面,而9既不是数组中最大的也不是最小的,所以我们要自定义排序方法。
这种解法对于两个数字a和b来说,如果将其都转为字符串,如果ab>ba则a排在前面,
比如9和34,由于934>349,所以9排在前面,再比如说30和3,由于303<330,所以3排在30的前面。
按照这种规则对原数组进行排序后,将每个数字转化为字符串再连接起来就是最终结果
源代码:
class Solution {public: string largestNumber(vector<int>& nums) { vector<string> strs; string res; for(auto num : nums) strs.push_back(to_string(num)); sort(strs.begin(), strs.end(),[](string &s1, string &s2){return s1+s2>s2+s1;}); //不能使用= for(auto str : strs) res += str; while(res[0] == '0' && res.size()>1) res.erase(0,1); return res; }};
面试题6:
题源:[Leetcode 402] Remove K Digits删除K个数字解题报告
题意:将给定的数字去掉k位,要使得留下来的数字最小
题解:这里采用贪心算法的思想,先来考虑如何去掉1位数字来获得最小的结果。
我最开始想的是去掉最大的一个数字,后来发现这个思路有问题。
举例来说,12219,去掉1位我们应该去掉哪个?去掉2,变成1219;去掉9,变成1221,显然,去掉2结果更小一些。
然而2是处在一个什么位置上呢?2是这个数字从左往右检索的第一个“峰值”。
意思是说,他比前一个数字大,也比后面一个数字大。
去掉这种值,获得的结果最小。去掉k个数字,可以理解为去掉1个数字的操作执行k次。
源代码:
class Solution {public: string removeKdigits(string num, int k) { while (k > 0) { int n = num.size(); int i = 0; while (i+1<n && num[i]<=num[i+1]) i++; num.erase(i, 1); k--; } // trim leading zeros int s = 0; while (s<(int)num.size()-1 && num[s]=='0') s++; num.erase(0, s); return num=="" ? "0" : num; }};
题源:[LeetCode 215]Kth Largest Element in an Array 数组中第k大的数字
题意:数组中第k大的数字
题解:解法有很多,这道题最好的解法应该是下面这种做法,用到了快速排序Quick Sort的思想。
源代码:
class Solution {public: //快速排序 int partition(vector<int>& nums, int low, int high){ //&千万不能忘记 int key = nums[low]; while(low < high){ while(low < high && nums[high] >= key) high--; //必须从右边开始,>=关系要分清 swap(nums[low], nums[high]); while(low < high && nums[low] <= key) low++; swap(nums[low], nums[high]); } return low; } int findKthLargest(vector<int>& nums, int k) { int low = 0, high = nums.size()-1; while(true){ int pos = partition(nums, low, high); if(pos == nums.size()-k) return nums[pos]; else if(pos < nums.size()-k) low = pos + 1; else high = pos - 1; } }}
第一次写博客,欢迎大家指正,谢谢!
- 程序员面试题总结一:排序算法
- 经典面试题-- 排序算法(一)
- 排序算法总结及面试题
- Java程序员基础面试题总结(一)
- 排序算法面试题
- 程序员面试题一
- 程序员面试题一
- 算法面试题一
- 算法面试题一
- 算法面试题总结
- 算法面试题总结
- 算法面试题总结
- 算法面试题总结
- 算法面试题总结
- 算法面试题总结
- 【IT面试题】排序算法
- 排序算法常见面试题
- .NET程序员面试题总结
- 数据链路层和物理层一些相关解释
- phpstorm 2017.1.3 最新版激活方法
- JDBC
- Tensorflow一些常用基本概念与函数
- 十进制数与ASCII码的转换
- 程序员面试题总结一:排序算法
- SLAM学习笔记(三)特征提取
- 视图与URLconf
- 【C语言】代码规范 内存管理
- 让无数社群为自己打工?你要用好这6大驱动力
- spark原理入门详解:包括生态、特点、概念等
- 2017年高校网络信息安全管理运维挑战赛部分题解
- JSP笔记一
- 带缩略图的图片切换