程序员面试题总结一:排序算法

来源:互联网 发布: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);    }};


面试题4:

题源:[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--]);        }    }};


面试题5:

题源:[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;    }};


面试题7:

题源:[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;        }    }}

第一次写博客,欢迎大家指正,谢谢!