面试常考算法题总结(二)
2016-08-30 17:41
351 查看
题目链接:试卷1和试卷2。
题目1:对于一个无序数组A,请设计一个算法,求出需要排序的最短子数组的长度。给定一个整数数组A及它的大小n,请返回最短子数组的长度。
测试样例:
代码如下:
分析:基本思路,全部遍历一遍,代码如下:
另一种思路是先找出整个数组中的最大值,最小值取数组两端的较小值,这个最大值和最小值的差值即为所求。
代码如下:
题目3:定义局部最小的概念。arr长度为1时,arr[0]是局部最小。arr的长度为N(N>1)时,如果arr[0]<arr[1],那么arr[0]是局部最小;如果arr[N-1]<arr[N-2],那么arr[N-1]是局部最小;如果0<i<N-1,既有arr[i]<arr[i-1]又有arr[i]<arr[i+1],那么arr[i]是局部最小。
给定无序数组arr,已知arr中任意两个相邻的数都不相等,写一个函数,只需返回arr中任意一个局部最小出现的位置即可。
分析:注意要考虑特殊情况,比如大小为0或者大小为1的情况,代码如下:
题目4:(子数组最大乘积)给定一个double类型的数组arr,其中的元素可正可负可0,返回子数组累乘的最大乘积。例如arr=[-2.5,4,0,3,0.5,8,-1],子数组[3,0.5,8]累乘可以获得最大的乘积12,所以返回12。
分析:这是一个动态规划问题。是leetcode中Maximum Product Subarray问题(链接:Maximum
Product Subarray)。代码如下:
分析:复杂度为O(N)的解法:
题目6:给定两个有序数组arr1和arr2,两个数组长度都为N,求两个数组中所有数的上中位数。
例如:
arr1 = {1,2,3,4};
arr2 = {3,4,5,6};
一共8个数则上中位数是第4个数,所以返回3。
arr1 = {0,1,2};
arr2 = {3,4,5};
一共6个数则上中位数是第3个数,所以返回2。
要求:时间复杂度O(logN)。
分析:要保证复杂度O(logN)肯定是要用二分查找,只不过我最开始一直没有找到结束的条件,以为是查找元素相等就退出。最后在网上查了,结束条件应该是每个数组都只剩下2个元素。首先取二者的中位数,在O(1)时间复杂度内求出,那么数组arr1的midValue
= 2,数组arr2的midValue = 4,则较小的元素midValue的左边所有元素,也就是midPosition个,和较大元素右边的所有元素,都要去掉,由于去掉的元素占所有元素的一 半,所以复杂度为O(logn)。只需要移动Lindex和Rindex的位置即可,直到 Lindex == Rindex - 1。
例如:
arr1 = {1,2,3,4,5};
arr2 = {3,4,5};
K = 1;
因为1为所有数中最小的,所以返回1;
arr1 = {1,2,3};
arr2 = {3,4,5,6};
K = 4;
因为3为所有数中第4小的数,所以返回3;
要求:如果arr1的长度为N,arr2的长度为M,时间复杂度请达到O(log(min{M,N}))。
分析:归并排序思想
题目1:对于一个无序数组A,请设计一个算法,求出需要排序的最短子数组的长度。给定一个整数数组A及它的大小n,请返回最短子数组的长度。
测试样例:
[1,5,3,4,2,6,7],7
返回:4
分析:
1
.先判断依次最小值是否在正确位置,直到找到不在正确位置最小值的应该在的位置,
作为最小需排序
的
起始点
2
.依次判断最大值是否在正确位置,直到找不到正确位置最大值应
该在的位置,作为最小需排序的末
尾点
3
.计算首末位点间的整数个数,即为需要排序的最短
子数组长度。
代码如下:
[2,7,3,1,1],5
返回:6
分析:基本思路,全部遍历一遍,代码如下:
另一种思路是先找出整个数组中的最大值,最小值取数组两端的较小值,这个最大值和最小值的差值即为所求。
代码如下:
class MaxGap { public: int findMaxGap(vector<int> A, int n) { int max=-1,min; for(int i=0;i<n;i++) if(A[i]>max) max=A[i]; min = A[0]>A[n-1]?A[n-1]:A[0]; return max-min; } };
题目3:定义局部最小的概念。arr长度为1时,arr[0]是局部最小。arr的长度为N(N>1)时,如果arr[0]<arr[1],那么arr[0]是局部最小;如果arr[N-1]<arr[N-2],那么arr[N-1]是局部最小;如果0<i<N-1,既有arr[i]<arr[i-1]又有arr[i]<arr[i+1],那么arr[i]是局部最小。
给定无序数组arr,已知arr中任意两个相邻的数都不相等,写一个函数,只需返回arr中任意一个局部最小出现的位置即可。
分析:注意要考虑特殊情况,比如大小为0或者大小为1的情况,代码如下:
class Solution { public: int getLessIndex(vector<int> arr) { int res; if(arr.size()==0) res = -1; else if(arr.size()==1) res = 0; else if(arr.size()==2){ if(arr[0]<arr[1]) res = 0; else res = 1; } else{ if(arr[0]<arr[1]) res = 0; else if(arr[arr.size()-1]<arr[arr.size()-2]) res = arr.size()-1; else{ for(int i = 1;i<arr.size()-1;++i){ if(arr[i]<arr[i-1]&&arr[i]<arr[i+1]){ res = i; break; } } } } return res; } };
题目4:(子数组最大乘积)给定一个double类型的数组arr,其中的元素可正可负可0,返回子数组累乘的最大乘积。例如arr=[-2.5,4,0,3,0.5,8,-1],子数组[3,0.5,8]累乘可以获得最大的乘积12,所以返回12。
分析:这是一个动态规划问题。是leetcode中Maximum Product Subarray问题(链接:Maximum
Product Subarray)。代码如下:
class Solution { public: double maxProduct(vector<double> arr) { if (arr.empty()) return 0; double maxNum = arr[0]; double minNum = arr[0]; double res = arr[0]; double maxEnd = 0; double minEnd = 0; int i = 0; /* max(arr[i])处的最大值和最小值在以下三个选项中 max(arr[i-1]) * arr[i] min(arr[i-1]) * arr[i] arr[i] */ for(i = 1; i < arr.size(); i++) { maxEnd = maxNum * arr[i]; minEnd = minNum * arr[i]; maxNum = max(max(maxEnd, minEnd), arr[i]); minNum = min(min(maxEnd, minEnd), arr[i]); res = max(res, maxNum); } return res; } };题目5:给定一棵完全二叉树的头节点head,返回这棵树的节点个数。如果完全二叉树的节点数为N,请实现时间复杂度低于O(N)的解法。
分析:复杂度为O(N)的解法:
/** struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } }; */ class Solution { public: int nodeNum(struct TreeNode* head) { if(head==NULL) return 0; else return 1+nodeNum(head->left)+nodeNum(head->right); } };思路2:
class Solution { public: int nodeNum(struct TreeNode* head) { if(head==NULL) return 0; int result=0; stack<struct TreeNode*> s; s.push(head); while(!s.empty()){ struct TreeNode* pTemp=s.top(); result++; s.pop(); if(pTemp->right!=NULL){ s.push(pTemp->right); } if(pTemp->left!=NULL){ s.push(pTemp->left); } } return result; } };
题目6:给定两个有序数组arr1和arr2,两个数组长度都为N,求两个数组中所有数的上中位数。
例如:
arr1 = {1,2,3,4};
arr2 = {3,4,5,6};
一共8个数则上中位数是第4个数,所以返回3。
arr1 = {0,1,2};
arr2 = {3,4,5};
一共6个数则上中位数是第3个数,所以返回2。
要求:时间复杂度O(logN)。
分析:要保证复杂度O(logN)肯定是要用二分查找,只不过我最开始一直没有找到结束的条件,以为是查找元素相等就退出。最后在网上查了,结束条件应该是每个数组都只剩下2个元素。首先取二者的中位数,在O(1)时间复杂度内求出,那么数组arr1的midValue
= 2,数组arr2的midValue = 4,则较小的元素midValue的左边所有元素,也就是midPosition个,和较大元素右边的所有元素,都要去掉,由于去掉的元素占所有元素的一 半,所以复杂度为O(logn)。只需要移动Lindex和Rindex的位置即可,直到 Lindex == Rindex - 1。
class Solution { public: int getUpMedian(vector<int> arr1, vector<int> arr2) { if (arr1.size()<=0 || arr2.size()<=0 || arr1.size() != arr2.size()) return 0; int L1 = 0; int R1 = arr1.size()-1; int L2 = 0; int R2 = arr2.size()-1; while (L1 < R1 && L2 < R2){ int mid1 = (R1+L1)/2; int mid2 = (R2+L2)/2; if (arr1[mid1] == arr2[mid2]) return arr1[mid1]; if (arr1[mid1] <arr2[mid2]){ //如果元素个数是奇数,那么R1+L1是偶数,者mid左右元素个数相同 //如果元素个数是偶数,那么R1+L1是奇数,者mid左边比右边少一个 mid1 = ((R1+L1)%2 == 0) ? mid1 : (mid1 + 1); L1 = mid1; R2 = mid2; }else{ mid2 = ((R2+L2)%2 == 0) ? mid2 : (mid2 + 1); R1 = mid1; L2 = mid2; } } return (arr1[L1] > arr2[L2]) ? arr2[L2] : arr1[L1]; } };当然如果采用一般的思路,将两个数组合并,再进行排序,即可找出结果,但复杂度高一些。
class Solution { public: int getUpMedian(vector<int> arr1, vector<int> arr2) { int len = arr1.size(); if(arr1[len-1]<=arr2[0]) return arr1[len-1]; else{ vector<int> arr; for(int i = 0;i<len;++i) arr.push_back(arr1[i]); for(int i = 0;i<len;++i) arr.push_back(arr2[i]); sort(arr.begin(),arr.end()); return arr[len-1]; } } };题目7:给定两个有序数组arr1和arr2,在给定一个整数k,返回两个数组的所有数中第K小的数。
例如:
arr1 = {1,2,3,4,5};
arr2 = {3,4,5};
K = 1;
因为1为所有数中最小的,所以返回1;
arr1 = {1,2,3};
arr2 = {3,4,5,6};
K = 4;
因为3为所有数中第4小的数,所以返回3;
要求:如果arr1的长度为N,arr2的长度为M,时间复杂度请达到O(log(min{M,N}))。
分析:归并排序思想
class Solution { public: int findKthNum(vector<int> arr1, vector<int> arr2, int kth) { int pos=0; int i=0,j=0; while(i<arr1.size()&&j<arr2.size()){ int flag=0; if(arr1[i]<arr2[j]){ i++; flag=1; }else{ j++; flag=2; } pos++; if(pos==kth){ if(flag==1) return arr1[i-1]; if(flag==2) return arr2[j-1]; } } if(j<arr2.size()) return arr2[j+kth-pos-1]; if(i<arr1.size()) return arr1[i+kth-pos-1]; return 0; } };和上一题一样,也可以直接合并数组,但是复杂度高:
class Solution { public: int findKthNum(vector<int> arr1, vector<int> arr2, int kth) { vector<int> arr; int len1 = arr1.size(),len2 = arr2.size(); for(int i = 0;i<len1;++i) arr.push_back(arr1[i]); for(int i = 0;i<len2;++i) arr.push_back(arr2[i]); sort(arr.begin(),arr.end()); return arr[kth-1]; } };
相关文章推荐
- 面试算法题总结(一)
- 微软面试、经典算法、编程艺术、红黑树4大系列总结
- 那些年我们面试过的单链表算法总结(一)
- 笔试、面试重点总结:算法基础、数据结构
- 笔试、面试重点总结:算法基础、数据结构
- 数据结构和算法面试总结
- 数据结构和算法面试总结
- iOS开发-一些面试算法总结
- 面试之图论[Graph],算法摘要总结
- 程序员编程艺术第一~四十章集锦与总结--面试、算法、编程
- 微软面试、经典算法、编程艺术、红黑树4大系列总结
- 微软面试、经典算法、编程艺术、红黑树4大系列总结
- 程序员编程艺术第一~十章集锦与总结--面试、算法、编程
- Top 10 Algorithms for Coding Interview 面试十大算法总结
- 面试总结之-查找算法分析
- 面试算法题总结(二)
- 微软面试、经典算法、编程艺术、红黑树4大系列总结
- 微软面试、经典算法、编程艺术、红黑树4大系列总结
- CSDN总结的面试中的十大算法
- 求职面试算法总结(感谢用心整理的小伙伴)