关于数组的面试题总结(三)
来源:互联网 发布:数组和指针的区别 知乎 编辑:程序博客网 时间:2024/05/29 07:39
再发一组关于数组的题目,其中部分来自一些公司的面试题(没有合适的oj来测试),部分来自leetcode。
暂时不给出解题思路和代码,待节后有时间再整理补充。(已全部更新)
1. 有序数组的二分查找
int binSearch(int array[], int low, int high, int target) { // 递归 if (low > high) return -1; int mid = low + ((high - low) >> 1); if (array[mid] > target) return binSearch(array, low, mid -1, target); if (array[mid] < target) return binSearch(array, mid+1, high, target); return mid; }
int binSearch(int array[], int low, int high, int target) { // 非递归 while(low <= high) { int mid = low + low + ((high - low) >> 1); if (array[mid] > target) high = mid - 1; else if (array[mid] < target) low = mid + 1; else return mid; } return -1; }
扩展:1). 关于数组的面试题1总结中的循环数组的查找;找到循环数组中的最小值;
2). 求整数的平方根sqrt(x),仅返回整数部分,可以采用二分查找的方法去试根。
2. 数组的排序(插入排序、冒泡排序、堆排序、快速排序和归并排序)
// 插入排序 ,虽然查找位置的时候可以用二分查找,但是同样需要移动后半部分的元素,复杂度并不减少void InsertSort(vector<int> &array){ int i, j; for(i = 1; i < array.size(); ++i) { int tmp = array[i]; for(j = i-1; j >= 0 && array[j] > tmp; --j) { array[j+1] = array[j]; } array[j+1] = tmp; }}
// 冒泡排序void BubbleSort(vector<int> &array){ int n = array.size(); for(int i = 0; i < n; ++i) { for(int j = 0; j < n-i-1; ++j) { if(array[j] > array[j+1]) swap(array[j], array[j+1]); } }}// 改进的冒泡排序void BubbleSort2(vector<int> &array){ int n = array.size(); for(int i = 0; i < n; ++i) { bool hasChange = false; for(int j = 0; j < n-i-1; ++j) { if(array[j] > array[j+1]) { swap(array[j], array[j+1]); hasChange = true; } } // 若本趟扫描没有任何替换,则数组已经有序 if(!hasChange) break; }}堆排序,需要注意两点:1). 很多教科书中计算左右子孩子一般是以数组下标为1开始来计数的,当我们从0开始计数时有差异;
2). 在调整堆的函数中一定要添加数组的长度n,而不是直接取vector的size!
// 调整大顶堆void maxHeapify(vector<int> &array, int idx, int n){ // 注意调整函数中需要带上数组的大小,因为排序的时候这个n一直在减小 int maxIdx = idx; if(2*idx+1 < n && array[2*idx+1] > array[maxIdx]) { maxIdx = 2*idx + 1; } if(2*idx+2 < n && array[2*idx+2] > array[maxIdx]) { maxIdx = 2*idx + 2; } if(maxIdx != idx) { swap(array[maxIdx], array[idx]); maxHeapify(array, maxIdx, n); }}// 堆排序void HeapSort(vector<int> &array){ int n = array.size(); for(int i = (n-1)/2; i >= 0; --i) { maxHeapify(array, i, n); } for(int i = n-1; i > 0; --i) { swap(array[0], array[i]); maxHeapify(array, 0, i); }}快速排序有两种不同的划分方法,第一种方法是算法导论正文中讲述的,它保证i左边(包括i)所有元素都是小于或者等于pivot,然后采用j从左到右依次判断,若遇到比pivot小的元素就与第i+1位(程序中先++i了,即第一个大于pivot的元素)互换。
另一种方法则是从左右两边同时扫描,保证l左边部分都是较小的元素,r右边部分都是较大的元素,但是尤其需要注意的是while语句中要检查边界,while结束后赋值。若想在左右两边的while循环都结束后再swap两者的值,会很容易出错,最好不要这样写。
// 快速排序int Partition(vector<int> &array, int l, int r){ int pivot = array[r]; int i = l - 1; // i及左边的元素都较小 for(int j = l; j < r; ++j) { if(array[j] <= pivot) { ++i; swap(array[i], array[j]); } } swap(array[i+1], array[r]); return i+1;}int Partition2(vector<int> &array, int l, int r){ int pivot = array[l]; while(l < r) { // 从两端到中间 while(l < r && array[r] >= pivot) --r; if(l < r) array[l++] = array[r]; while(l < r && array[l] <= pivot) ++l; if(l < r) array[r--] = array[l]; } array[l] = pivot; return l;}void QuickSortHelper(vector<int> &array, int l, int r){ if(l >= r) return; int mid = Partition(array, l, r); //int mid = Partition2(array, l, r); QuickSortHelper(array, l, mid-1); QuickSortHelper(array, mid+1, r);}void QuickSort(vector<int> &array){ int n = array.size(); QuickSortHelper(array, 0, n-1);}用递归写,需要额外的空间。
// 归并排序void Merge(vector<int> &array, int low, int mid, int high){ vector<int> tmp; int i = low; int j = mid + 1; while(i <= mid && j <= high) { if(array[i] <= array[j]) tmp.push_back(array[i++]); else tmp.push_back(array[j++]); } while(i <= mid) { tmp.push_back(array[i++]); } while(j <= high) { tmp.push_back(array[j++]); } for(int i = 0; i < tmp.size(); ++i) { array[low + i] = tmp[i]; }}void MergeSortHelper(vector<int> &array, int l, int r){ if(l >= r) return; int mid = l + ((r-l) >> 1); MergeSortHelper(array, l, mid); MergeSortHelper(array, mid+1, r); Merge(array, l, mid, r);}void MergeSort(vector<int> &array){ int n = array.size(); MergeSortHelper(array, 0, n-1);}
3. 循环数组中的最大字段和(《编程之美》)
这里可以刷这道题:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1050
long long maxSumSubArray(const vector<int> &array){ long long sum = 0; long long tmp = 0, tmp1 = 0; long long max = 0; long long min = INT_MAX; for(int i = 0; i < array.size(); ++i) { sum += array[i]; if(tmp > 0) tmp += array[i]; else tmp = array[i]; if(tmp > max) max = tmp; if(tmp1 < 0) tmp1 += array[i]; else tmp1 = array[i]; if(tmp1 < min) min = tmp1; } max = max > sum - min ? max : sum - min; return max;}
4. 求整数数组中最长的连续序列(Longest Consecutive Sequence)
例如,给定数组[100, 4, 200, 1, 3, 2],最长的连续序列是[1,2,3,4],应该输出其长度4
int longestConsecutive(vector<int> &num) { if(num.size() == 0) return 0; int maxlen = 1; map<int, int> record; for(size_t i = 0; i < num.size(); ++i) { int val = num[i]; if(record[val] != 0) continue; record[val] = 1; int l = record[val - 1]; int r = record[val + 1]; //cout<<val<<" "<<l<<" "<<r<<endl; record[val - l] = 1 + r + l; record[val + r] = 1 + r + l; if(1 + r + l > maxlen) maxlen = 1 + r + l; } return maxlen; }
5. 求随机整数数组中最长等差数列长度
int longestSubArray(vector<int> &array){ int n = array.size(); vector<vector<int> > dp; vector<int> tmp(n, 2); dp.assign(n, tmp); sort(array.begin(), array.end()); int maxLen = 2; for(int i = 1; i < n-1; ++i) { int j = i-1, k = i+1; while(j >= 0 && k < n) { if(array[j] + array[k] > 2 * array[i]) --j; else if(array[j] + array[k] < 2 * array[i]) ++k; else { dp[i][k] = 1+dp[j][i]; if(dp[i][k] > maxLen) maxLen = dp[i][k]; --j; ++k; } } } return maxLen;}
6. 找出大于0的丢失的最小数字
给定一个无序的整数数组,怎么找到第一个大于0,并且不在此数组的整数。比如[1,2,0] 返回 3, [3,4,-1,1] 返回 2。最好能O(1)空间和O(n)时间。
http://www.ituring.com.cn/article/56179
int findLostPosNum(vector<int> &array){ int n = array.size(); for(int i = 0; i < n; ) { if(array[i] == i+1 || array[i] > n || array[i] <= 0) { ++i; } else swap(array[array[i]-1], array[i]); } for(int i = 0; i < array.size(); ++i) { //cout << array[i] << endl; if(array[i] != i+1) return i+1; } return array.back()+1;}
7. 最长递增子数组
// 方法一: dpint LIS1(const vector<int> &array){ // 用dp[i]记录以第i个元素作为最后一个元素的递增子数组的长度 int n = array.size(); vector<int> dp(n, 0); int lis = 0; for(int i = 0; i < n; ++i) { dp[i] = 1; for(int j = 0; j < i; ++j) { if(array[i] > array[j] && dp[i] < dp[j] + 1) { dp[i] = dp[j] + 1; if(dp[i] > lis) { lis = dp[i]; } } } } return lis;}// 方法二: dp + binary searchint binSearch(const vector<int> num, int target){ int l = 0, r = (int)num.size() - 1; while(l <= r) { int mid = l + ((r - l) >> 1); if(num[mid] == target) return mid; else if(num[mid] < target) l = mid+1; else r = mid - 1; } return l;}int LIS2(const vector<int> &array){ // 用dp[i]记录长度为i+1的递增子数组的最小的末尾元素值 if(0 == array.size()) return 0; vector<int> dp; dp.push_back(array[0]); for(int i = 1; i < array.size(); ++i) { int pos = binSearch(dp, array[i]); if(pos == dp.size()) dp.push_back(array[i]); else if(dp[pos] > array[i]) dp[pos] = array[i]; } return dp.size();}
扩展:叠罗汉。给出几组数据,如(20,30),(24,25),(30,40),(32,41),(x,y)中,x 代表身高,y代表体重。叠罗汉,下面的人要比上面的人身高低、体重小。问最多叠几层?
8. 两个有序数组A,B(长度不等),从A,B中分别任意选取a,b,求min{|a-b|}
int minDistofAB(const vector<int> &A, const vector<int> &B){ // 采用归并的思想,但是不需要真正的归并,时间复杂度O(m+n) if(0 == A.size() || 0 == B.size()) return -1; int idxa = 0, m = A.size(); int idxb = 0, n = B.size(); int minDist = INT_MAX; while(idxa < m && idxb < n) { int tmp = abs(A[idxa] - B[idxb]); if(tmp < minDist) minDist = tmp; if(0 == minDist) return minDist; if(A[idxa] <= B[idxb]) ++idxa; else ++idxb; } return minDist;}
扩展:有n个有序数组,每个数组中取一个数字,使得得到的数列的最大值与最小值的差异最小。
对于n个有序数组,同样可以采用归并的思想,但是需要利用最小堆保存从每个数组中选取的数字,可以快速计算这些值的最小值,而最大值用一个临时变量保存即可。
关于最小堆的调整,每次移走最小堆的堆顶元素x,而补充该位置的元素则来自与x相同的那个数组,具体做法可以参见败者树。
9. 分糖果问题,n个孩子站成一排,每个人有一个分数值,要求每个孩子至少有一个糖果,且比相邻孩子分数高的孩子得到的糖果也应该比邻居多。
int candy(vector<int> &ratings){ // 从左向右扫描一遍,再从右向左扫描一遍 int n = ratings.size(); if(0 == n) return 0; vector<int> candy(n, 1); for(int i = 1; i < n; ++i) { if(ratings[i] > ratings[i-1]) candy[i] = candy[i-1] + 1; } int ret = candy[n-1]; for(int i = n-2; i >= 0; --i) { if(ratings[i] > ratings[i+1]) { candy[i] = max(candy[i], candy[i+1] + 1); } ret += candy[i]; } return ret;}
10.最大蓄水(Container With Most Water),数组a[0..n-1],其中a[i]表示坐标(i, a[i])有一条垂直于x轴的直线,两条直线和x轴一起可以组成一个蓄水池,根据数组a求出最大蓄水量(宽*高)。
int maxArea(vector<int> &height) { size_t len = height.size(); if(len <= 1) return 0; size_t low = 0, high = len - 1; int maxa = 0; while (low < high) { int h = 0, wide = high - low; if(height[low] < height[high]) { h = height[low++]; } else { h = height[high--]; } int tempa = h * wide; if(tempa > maxa) maxa = tempa; } return maxa; }
0 0
- 关于数组的面试题总结(三)
- 关于数组的面试题总结(一)
- 关于数组的面试题总结(二)
- 关于数组的面试题
- 关于数组的面试题
- 关于数组的面试题
- 关于数组指针的一道面试题
- 关于数组的面试笔试题
- 关于字符串的面试题总结
- 关于线程的面试题总结
- 关于阶乘的面试题总结
- 面试题集合--关于数组
- Android 面试题总结(三)
- 面试题总结(三)
- 关于数组与指针的一个面试题
- 关于C数组指针的一道面试题
- 上两道js面试题,关于数组字符串 之间的转化
- 三道关于面向对象设计的面试题
- java类与对象的区别
- vim编码方式配置的学习和思考
- Linux增加分区大小
- 杀进程:App主动杀(Process.killProcess),内存不够内核杀(LowMemoryKiller),手动停止(killPackageProcesses),最近任务(removeTask)
- ★cookie与session区别
- 关于数组的面试题总结(三)
- IOS 服务评测
- Django-Rest-Framework 教程: 快速入门
- 已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数
- android充电
- spring定时任务+线池程实现
- AlphaAnimation 、AnimationDrawable
- 编写剪刀(scissor)、石头(stone)、布(cloth)游戏
- 最全中文停用词表整理(1893个)