广州4399面试题(一)

来源:互联网 发布:linux mv r 编辑:程序博客网 时间:2024/06/10 09:04

题目描述

现给定一个含有n个元素的数组,请随机获取其中的m个元素(不能重复获取)。

算法描述

首先,随机获取元素,可以使用rand() % 数组长度

其次,要保证元素的不重复获取,只需将获取的元素从原数组中移除即可,但是每次都进行删除操作,需要频繁的移动数组元素,其复杂度很高;现在,我们换一种思路,将获取的元素与原数组最后的元素进行交换,再将数组的长度减一,那么就可以做到O(1)复杂度将其移除;详见下图:




















此算法的时间复杂度为O(n),其只与要获取的m个数有关,在n和m相差非常悬殊的时候,效率非常高。

程序源码

[cpp] view plaincopyprint?
  1. #include <iostream>  
  2. #include <vector>  
  3. #include <algorithm>  
  4. #include <iterator>  
  5.   
  6. using namespace std;  
  7.   
  8. typedef int ErrorType;  
  9.   
  10. const ErrorType ErrSucceed          =   0;  
  11. const ErrorType ErrInvalidRange     =   10;  
  12. const ErrorType ErrUnknown          =   100;  
  13.   
  14. template <typename ItemType>  
  15. ErrorType GetRandItemsFromArray(vector<ItemType> &items,  
  16.                                 const size_t itemCount,   
  17.                                 vector<ItemType> &result)  
  18. {  
  19.     // 边界检测  
  20.     if (items.size() < itemCount)  
  21.         return ErrInvalidRange;  
  22.   
  23.     // 将结果向量清空,并预留足够的空间,防止多次分配导致的性能开销。  
  24.     result.clear();  
  25.     result.reserve(itemCount);  
  26.   
  27.     // 注意差1的边界错误  
  28.     size_t itemsLength = items.size() - 1;  
  29.   
  30.     // 算法描述见正文  
  31.     for (size_t i = 0; i < itemCount; ++i)  
  32.     {  
  33.         int tmpIndex = rand() % itemsLength;  
  34.         result.push_back(items[tmpIndex]);  
  35.         swap(items[tmpIndex], items[itemsLength]);  
  36.         --itemsLength;  
  37.     }  
  38.   
  39.     return ErrSucceed;  
  40. }  
  41.   
  42. int main()  
  43. {  
  44.     vector<int> vec;  
  45.     for (int i = 0; i < 100; ++i)  
  46.         vec.push_back(i);  
  47.     vector<int> res;  
  48.     for (int i = 0; i < 10; ++i)  
  49.     {  
  50.         GetRandItemsFromArray(vec, 10, res);  
  51.         copy(res.begin(), res.end(), ostream_iterator<int>(cout, " "));  
  52.         cout << endl;  
  53.     }  
  54.   
  55.     return 0;  
  56. }  

总结

题目本身不难,但是要注意边界的校验,错误处理,代码可读性,数据抽象,时间及空间复杂度。另外,如果是现场写代码,最好问面试官原始数组是否允许修改!

0 0
原创粉丝点击