算法面试(一)

来源:互联网 发布:网络教育怎么报名时间 编辑:程序博客网 时间:2024/03/29 13:22
之前面试的时候,遇到了许多关于基本算法的题目,对于其代码的编写以及特殊情况下的优化及改进等,及算法相关的学习有了更多的感悟与领会,与大家分享一下,此处以快排讲解为例;

快排的核心思想很简单:就是先选择一个杠杆元素(一般选第一个数),对剩下元素遍历,大的放右边,小的放左边;然后对于两边元素再次用以上方法进行递归处理;

基本的代码实现在我的以前博客(排序二)中已经介绍过了,此处借鉴一个简洁代码:

// v为pivot,初始存储在arr[0]的位置 int j = 0; // 循环过程保持 arr[0...j] < v ; arr[j+1...i) > v for( int i = l + 1 ; i <= n ; i ++ )     if( arr[i] < v )         swap( arr[++j] , arr[i] ); swap( arr[l] , arr[j]); // 此时,j指向pivot的正确位置实例:  4 8 3 0 5 2 7  4 j=0  4 8   4 3 8 j=1  4 3 0 8 j=2  4 3 0 8 5   4 3 0 2 8 5 j=3  4 3 0 2 8 5 7  2 3 0 4 8 5 7我们知道对于快速排序算法,当元素排序是随机无序的时候,也就是当每递归完一次的时候,其元素大约成双等分时其效率是最高的,类似于二叉排序树,时间复杂度为O(n*lg n);然而大多数情况下事与愿违,当元素接近有序或者拥有大量重复元素时其效率将大大降低为O(n^2),所以对于此种情况我们需要考虑在内,提出以下解决办法:(1)如果我们一开始不知道数组是否基本有序,那么对于杠杆元素的选择上,我们可以实现随机选择一个元素作为pivot,这样同样可以降低有序的概率从而整体提高排序效率;(2)如果我们事先知道数组含有大量重复元素,则对于上面算法还可以再次改进,称为三路快排:小于的为一路,等于的为一路,大于的为一路,算法如下:// v为pivot,初始存储在arr[0]的位置 int lt = 0; // 循环过程中保持 arr[1...lt] < v int i = 1; // 循环过程中保持 arr[lt+1...i) == v int gt = n + 1; // 循环过程中保持 arr[gt...n] > v while( i < gt ){     if( arr[i] < v ){         swap( arr[i++], arr[lt+1]); lt ++;     } else if( arr[i] > v ){         swap( arr[i], arr[gt-1]); gt --;     } else      // arr[i] == v         i ++;     } swap( arr[l] , arr[lt] ); // 此时 arr[lt...gt-1]部分为数组中元素等于v的部分 // 之后只需要递归地对arr[l...lt-1]和arr[gt...r]两部分进行三路快排即可基于比较的排序算法,其时间复杂度至少为O(nlogn).扩展面试题:有一个数组,其中的元素取值只有可能是012。为这样一个数组排序。/// 解法一:直接使用排序接口,时间复杂度O(nlogn) class Solution { public:     void sortColors(vector<int>& nums) {         sort( nums.begin(), nums.end() );         return;     } };// 解法二:基于计数排序的解法,时间复杂度O(n),需要两遍遍历 ,//第一次统计元素个数,第二次放回原数组class Solution { public:     void sortColors(vector<int>& nums) {        int count[3] = {0}; // count[i]表示元素i的个数         for( int i = 0 ; i < nums.size() ; i ++ ){             assert( nums[i] >= 0 && nums[i] <= 2 );             count[ nums[i] ] += 1;        } int index = 0; for( int i = 0 ; i < count[0] ; i ++ ) // 安置count[0]个0     nums[index++] = 0; for( int i = 0 ; i < count[1] ; i ++ ) // 安置count[1]个1     nums[index++] = 1; for( int i = 0 ; i < count[2] ; i ++ ) // 安置count[2]个2     nums[index++] = 2; return; } };// 解法三:基于三路快排的partition的解法,时间复杂度O(n),只需要一边遍历 class Solution { public:     void sortColors(vector<int>& nums) {         int i = 0; // nums[0..<i) == 0         int j = 0; // nums[i..<j) == 1         int k = nums.size(); // nums[k..<n) == 2         while( j < k ){             if( nums[j] == 1 ) j++;             else if( nums[j] == 0 ) swap( nums[i++] , nums[j++] );             else{   // nums[j] == 2                 assert( nums[j] == 2 );                 swap( nums[j] , nums[k-1] ); k --; }         }         return;       } };

借鉴有感:http://www.imooc.com/article/16141

原创粉丝点击