您的位置:首页 > 职场人生

面试常考算法题总结(二)

2016-08-30 17:41 351 查看
题目链接:试卷1试卷2

题目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];
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法与数据结构