关于数组的面试题总结(三)

来源:互联网 发布:数组和指针的区别 知乎 编辑:程序博客网 时间: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
原创粉丝点击