3.2 排序相关题目

几乎有序的数组,即如果把数组排好序的话,每个元素移动的距离不超过k,k对于数组长度来说很小。用什么排序方法?

插入排序 O(N*k)

改进后堆排序 O(N*logk)

class ScaleSort {
public:
    vector<int> sortElement(vector<int> A, int n, int k) {
        // write code here\\
        //堆化数组,大小为k的数组的最后一个元素的下边为k-1,它的父节点下标为(k-1-1)/2
        if(n==0||n<k||k<=1)return A;
        vector<int> C;
        for(int s=0;s<k;s++){
            C.push_back(A[s]);
        }

        int first=(k-2)/2;
        for(;first>=0;first--){//这个循环非常重要!!!!!
        MinHeapFixdown(C,first,k);
        }

        int count=0;
        while(count<n-k){
        A[count]=C[0];
        C[0]=A[count+k];
            count++;
        MinHeapFixdown(C,0,k);//代表从第0个元素开始,对大小为k的堆进行调整,调整成小根堆
        }//上面结束的时候得到的是一个小根堆,但是并不是将小根堆从上到下从左到右输出到B就可以了,而是还是一个一个的输出调整
        //下面需要将A数组中的前k个数据赋值给B
        while(k>=1&&count<n){
            A[count]=C[0];
            count++;
            C[0]=C[k-1];
            k--;
            MinHeapFixdown(C,0,k);
        }
        return A;
    }
    void MinHeapFixdown(vector<int> &C,int i,int n){
         int min;
        int current=C[i];
        while(2*i+1<n){
            min=2*i+1;
            if(2*i+2<n){
                if(C[min]>C[2*i+2])
                    min=2*i+2;
            }
            if(current>C[min])
                {
                  C[i]=C[min];
                  i=min;

            }else{
                break;
            }
            }
        C[i]=current;//之所以放在这里是为了如果2*i+1大于n的话,而此时A[i]的位置还空着话,就要在这里进行赋值
        }
};

判断数组中是否有重复值,要求空间复杂度为O(1)

没有空间复杂度的限制,可以用哈希表

有空间限制,先排序,然后再判断,采用堆排序,非递归的堆排序,如果采用递归的堆排序,时间复杂度为O(logN)

class Checker {
public:
     void heapSort(vector<int> &a,int n){
          int i=(n-1-1)/2;
            for(;i>=0;i--){
               MaxHeapFixdown(a,i,n);
            }
            int k=n-1;
            while(k>=0){
            int temp=a[0];
            a[0]=a[k];
            a[k]=temp;
            MaxHeapFixdown(a,0,k);
                 k--;
            }    
        }

           void MaxHeapFixdown(vector<int> &a, int i,int n){
            //从i开始对长度为n的向量a进行调整,调整成为大顶堆
               int max=i;
               int current=a[max];
            while(2*i+1<n){
                if(current<a[2*i+1])
                    max=2*i+1;
                if(2*i+2<n&&a[2*i+2]>a[2*i+1]&&a[2*i+2]>current)
                    max=2*i+2;
                if(i!=max){
                a[i]=a[max];
                i=max;
                }else{
                    break;
                }
            }
               a[i]=current;

        }

    bool checkDuplicate(vector<int> a, int n) {
        // 利用非递归的堆排序,所以要借助于循环!

         heapSort(a,n);
        for(int i=0;i<n-1;i++){
            if(a[i]==a[i+1]){
                return true;
            }
        }
        return false;
    }
};

两个有序数组合并为一个数组,第一个数组空间正好可以容纳所有元素

从后往前进行覆盖数组A,直到数组B为空

class Merge {
public:
    int* mergeAB(int* A, int* B, int n, int m) {
        // write code here
        int i=n-1;
        int j=m-1;
        int count=n+m-1;
        while(i>=0&&j>=0){
            if(A[i]>B[j]){
                A[count]=A[i];
                count--;
                i--;
            }else{
                A[count]=B[j];
                count--;
                j--;
            }
        }
        while(i>=0){
           A[count]=A[i];
           count--;
           i--;
        }
        while(j>=0){
           A[count]=B[j];
           count--;
           j--; 
        }
        return A;
    }
};

三色排序

class ThreeColor {
public:
    vector<int> sortThreeColor(vector<int> A, int n) {
        // write code here
    //其中最左边的left指向的是第一个不为0的数据;这个数据只可能为0或者1
        //最右边的right指向的是第一个不为2的数据,这个数据可能为0 1 2都有可能;
         int left=0;
         int right=n-1;
         int cur=0;
         int temp;
        while(cur<=right){
            if(A[cur]==1)
                cur++;
            else if(A[cur]==0){
                temp=A[cur];
                A[cur]=A[left];
                A[left]=temp;
                cur++;
                left++;
            }else if(A[cur]==2){
                temp=A[cur];
                A[cur]=A[right];
                A[right]=temp;
                right--;
        }
    }
        return A;
    }
};

有序矩阵查找,从右上开始找 O(M+N) O(1)

class Finder {
public:
    bool findX(vector<vector<int> > mat, int n, int m, int x) {
        // write code here
        int j=m-1;//代表列
        int i=0;//代表行
        while(j>=0&&i<=n-1){
            if(mat[i][j]>x){
                i=i;
                j=j-1;  
        }
            else if(mat[i][j]<x){
                i=i+1;
                j=j;
            }
            else if(mat[i][j]==x){
                return true;
        }
        }
        return false;
    }
};

最短子数组, O(n) O(1)

class Subsequence {
public:
    int shortestSubsequence(vector<int> A, int n) {
        // write code here
        int max,min,right,left;
        max=A[0];
        min=A[n-1];
        right=0;
        left=0;
        for(int i=0;i<n;i++){
            if(A[i]>max)
                max=A[i];
            else if(A[i]<max){
                right=i;
            }
        }
        for(int j=n-1;j>=0;j--){
            if(A[j]<min)
                min=A[j];
            else if(A[j]>min){
                left=j;
        }
        }
        if(right==0&&left==0){
            return 0;
        }
        else{
            return  (right-left+1);
        }
    }

};

排序之后相邻两数最大差值,采用桶排序 O(N) O(N)

class Gap
{
public:
  int
  maxGap (vector<int> A, int n)
  {
    // write code here
    int max = A[0];
    int min = A[0];
    for (int i = 0; i < n; i++)
      {
    if (A[i] < min)
      min = A[i];
    if (A[i] > max)
      max = A[i];
      }
    //一共有n+1个桶,最后一个桶放最大值
    int interval = max - min; //必须用double类型,如果用整形,区间的计算长度经常都是分数,就会失真!!!
    //可以申请两个数组,长度都是n,一个存放每个桶中的最大值,一个存放每个桶中的最小值
    //int interval=(max-min)/n;一开始本来想直接计算出区间的,但是区间通常都是分数,如果变成int类型就会失真,导致后面的结果发生错误!!!
    vector<int> maxBucket (n + 1, INT_MIN);
    vector<int> minBucket (n + 1, INT_MAX);
    int index;
    for (int i = 0; i < n; i++)
      {
    index = (A[i] - min) * n / interval; //这里为了让结果不失真,将本来是(A[i] - min)/((max-min)/n)进行了整顿直接变成这个公式,防止了Bucket数组的越界以及结果失真
    if (A[i] > maxBucket[index])
      maxBucket[index] = A[i];
    if (A[i] < minBucket[index])
      minBucket[index] = A[i];
      }
    int result = 0;
    int pre = maxBucket[0]; //需要注意的是0桶里一定至少有一个值,就是整个数组中的最小值
    for (int j = 1; j < n+1; j++)//这里一定是n+1!!!!!!因为是n+1个桶啊啊啊啊啊!!!!!!
      {
    if (minBucket[j] != INT_MAX)
      { //这里的判断就是为了越过空桶!!!
        if (minBucket[j] - pre > result)
          result = minBucket[j] - pre; //注意这里最好不要使用max min这样的<algrithm>头文件中的函数,因为不支持!
        pre = maxBucket[j];
      }

      }
    return result;

  }
};

results matching ""

    No results matching ""