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

原创 2016年08月30日 17:41:03

题目链接:试卷1试卷2

题目1:对于一个无序数组A,请设计一个算法,求出需要排序的最短子数组的长度。给定一个整数数组A及它的大小n,请返回最短子数组的长度。

测试样例:
[1,5,3,4,2,6,7],7
返回:4

分析:1.先判断依次最小值是否在正确位置,直到找到不在正确位置最小值的应该在的位置,

作为最小需排序起始点2.依次判断最大值是否在正确位置,直到找不到正确位置最大值应

该在的位置,作为最小需排序的末尾点3.计算首末位点间的整数个数,即为需要排序的最短

子数组长度。

代码如下:

class ShortSubsequence {
public:
    int findShortest(vector<int> A, int n) {
        vector<int> B = A;
        sort(A.begin(),A.end());
        int pos1 = 0,pos2 = 0;
        for(int i = 0;i<n;++i){
            if(A[i]!=B[i]){
                pos1 = i;
                break;
            }
        }
        for(int i = n-1;i>=0;--i){
            if(A[i]!=B[i]){
                pos2 = i;
                break;
            }
        }
        if(pos1==0&&pos2==0)
            return 0;
        else
            return pos2-pos1+1;
    }
};
题目2:给定一个长度为N(N>1)的整型数组A,可以将A划分成左右两个部分,左部
分A[0..K],右部分A[K+1..N-1],K可以取值的范围是[0,N-2]。求这么多划分方案中,左
部分中的最大值减去右部分最大值的绝对值,最大是多少?给定整数数组A和数组的大
n,请返回题目所求的答案。
测试样例:
[2,7,3,1,1],5
返回:6
分析:基本思路,全部遍历一遍,代码如下:
class MaxGap {
public:
    int findMaxGap(vector<int> A, int n) {
        vector<int> v;
        int res = 0;
        for(int i = 0;i<n-1;++i){
            int max1 = 0,max2 = 0;
            for(int j = 0;j<=i;++j){
                if(A[j]>max1)
                    max1 = A[j];
            }
            for(int j = i+1;j<n;++j){
                if(A[j]>max2)
                    max2 = A[j];
            }
            v.push_back(abs(max1-max2));
        }
        for(int i = 0;i<v.size();++i){
            if(res<v[i])
                res = v[i];
        }
        return res;
    }
};
另一种思路是先找出整个数组中的最大值,最小值取数组两端的较小值,这个最大值和最小值的差值即为所求。

代码如下:

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];
    }
};
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

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

题目链接:面试常考算法题(一) 题目1:请把一张窄纸条竖着放在桌上,然后从纸条的下边向上对折,压出折痕后再展开。此时有1条折痕,突起的一面向指向纸条的背面,这条折痕叫做“下”折痕;突起的向指向纸条正面...

JAVA实现单向链表反转

本片内容代码反转算法为转载!!上一篇《Java实现单向链表反转》中存在一个last是从前往后反转的。本片文章要实现的是从后往前反转。大体思路差不多。就是在临时变量.cur,pre的替换保存花费了些心思...
  • djx0226
  • djx0226
  • 2013年06月04日 03:11
  • 982

轻量级JavaEE企业应用实战(四)

JSP的7个动作指令 jsp:forward:执行页面转向,将请求的处理转发到下一个页面 jsp:param:用于传递参数,必须与其他支持参数的标签一起使用 jsp:include:动态引入一个JSP...

笔试面试常考排序算法总结

在笔试面试的过程中,常常会考察一下常见的几种排序算法,包括冒泡排序,插入排序,希尔排序,直接选择排序,归并排序,快速排序,堆排序等7种排序算法,下面将分别进行讲解。另外,我自己在学习这几种算法过程中,...
  • hmxz2nn
  • hmxz2nn
  • 2016年11月11日 20:47
  • 486

牛客面试常考算法题精讲部分题目c/c++代码

最近在看牛客网左程云老师讲解常考面试题(http://www.nowcoder.com/live/courses),感觉讲的非常好,但是给的代码都是java的,故我这里用c++自己写了一遍,作为一个记...

面试常考算法题 局部最小 求二叉树结点 求两个数组中所有数的上中位数 两个数组的所有数中第K小的数

定义局部最小的概念。arr长度为1时,arr[0]是局部最小。arr的长度为N(N>1)时,如果arr[0] 给定无序数组arr,已知arr中任意两个相邻的数都不相等,写一个函数,只需返回arr中任...

Java实现面试常考的算法

Java实现面试常考的算法 查找算法 排序算法 插入排序 选择排序 冒泡排序 快速排序Java实现面试常考的算法 我自己总结了几个平时面试问得一些算法题, 都是非常非常基础的问题. 查找算法 ...

面试常考之排序算法

总结一下面试常常遇到的基础排序算法(默认升序),方便复习: 1.选择排序 思想:每一趟选出最小值 复杂度分析:最坏情况O(n^2),最好情况O(n^2),平均情况O(n^2),额外空间O(1...
  • rido_
  • rido_
  • 2017年06月16日 17:48
  • 74

面试常考的常用数据结构与算法

数据结构与算法,这个部分的内容其实是十分的庞大,要想都覆盖到不太容易。在校学习阶段我们可能需要对每种结构,每种算法都学习,但是找工作笔试或者面试的时候,要在很短的时间内考察一个人这方面的能力,把每种结...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:面试常考算法题总结(二)
举报原因:
原因补充:

(最多只允许输入30个字)