zoukankan      html  css  js  c++  java
  • 3299 有序数组合并求第K大问题

    题目描述 Description

    给出两个有序数组A和B(从小到大有序),合并两个有序数组后新数组c也有序,询问c数组中第k大的数

    假设不计入输入输出复杂度,你能否给出一个O(logN)的方法?

    输入描述 Input Description

    第一行输入三个整数n、m和k

    第二行输入n个用空格隔开的整数表示数组A

    第三行输入m个用空格隔开的整数表示数组B

    输入保证A和B数组非递减

    输出描述 Output Description

    合并两个数组之后的第k大的数

    样例输入 Sample Input

    2 3 4

    1  2

    1 1 5

    样例输出 Sample Output

    2

    数据范围及提示 Data Size & Hint

    1<=n,m<=1000000

    1<=k <=n+m

    算法一:O(m+n+k)

    做类似于归并排序的合并,但是没有使用额外的空间。

     1 #include <stdio.h>
     2 long long n,m,k,a[1000005],b[1000005];
     3 long long findKthSMallest()
     4 {
     5     int ai=0,bi=0;
     6     while(k>0)
     7     {
     8         if(ai<n&&bi<m)
     9         {
    10             if(a[ai]<=b[bi]) 
    11             {
    12                 if(k==0) return a[ai];
    13                 ai++;
    14             }
    15             else if(b[bi]<=a[ai])
    16             {
    17                 if(k==0) return b[bi];
    18                 bi++;
    19             }
    20         }
    21         else if(ai<n&&bi==m)
    22         {
    23             if(k==0) return a[ai];
    24             ai++;
    25         }
    26         else if(ai==n&&bi<m)
    27         {
    28             if(k==0) return b[bi];
    29             bi++;
    30         }
    31         else return -1;
    32         
    33         k--;
    34     }
    35 }
    36 int main(int argc, char *argv[])
    37 {
    38     int i;
    39     scanf("%d%d%d",&n,&m,&k);
    40     for(i=0;i<n;i++) scanf("%d",&a[i]);
    41     for(i=0;i<m;i++) scanf("%d",&b[i]);
    42     printf("%d
    ",findKthSMallest());
    43     return 0;
    44 }
    View Code

    下面的代码是同样的思路,但是代码比较简洁易懂:

     1 #include <stdio.h>
     2 int n,m,k,a[1000005],b[1000005];
     3 int findKthSMallest(int a[],int n,int b[],int m,int k)
     4 {
     5     int a_offset = 0, b_offset = 0;
     6     if(n+m<k) return -1;
     7     
     8     while(true)
     9     {
    10         if(a_offset<n)
    11         {
    12             while (b_offset == m || a_offset<n&&a[a_offset] <= b[b_offset])
    13             {
    14                 if(a_offset+1 + b_offset == k) return a[a_offset];
    15                 a_offset++;
    16             }
    17         }
    18         if(b_offset<m)
    19         {
    20             while (a_offset == n || b_offset<m&&a[a_offset] >= b[b_offset])
    21             {
    22                 if (a_offset + b_offset+1 == k) return b[b_offset];
    23                 b_offset++;
    24             }
    25         }
    26     }
    27 }
    28 int main(int argc, char *argv[])
    29 {
    30     int i;
    31     scanf("%d%d%d",&n,&m,&k);
    32     for(i=0;i<n;i++) scanf("%d",&a[i]);
    33     for(i=0;i<m;i++) scanf("%d",&b[i]);
    34     printf("%d
    ",findKthSMallest(a,n,b,m,k));
    35     return 0;
    36 }

    第二段代码参考自:在线疯狂的博客,原文代码有误,已经修正。

    第三种写法:省一些空间,b[ ]并没有提前完整输入。

     1 #include <stdio.h>
     2 int n,m,k,a[1000005];
     3 int main(int argc, char *argv[])
     4 {
     5     int i,j,bTemp,kIndex,kValue=0,f;
     6     scanf("%d%d%d",&n,&m,&k);
     7     for(i=0;i<n;i++) scanf("%d",&a[i]);
     8 
     9     i=0,kIndex=0,f=0;
    10     for(j=0;j<m||i<n;j++) // i是a[]的下标,j是b[]的下标 
    11     {
    12         //for的语句条件和这里的if条件是防止b[]扫描完了却未曾寻找到第k个数.
    13         //这个时候需要继续循环,在a[]中寻找,但是不再输入 
    14         if(j<m) scanf("%d",&bTemp);
    15         
    16         while(i<n||j<m)
    17         {
    18             if(j==m||i<n&&a[i]<=bTemp)
    19             {
    20                 kIndex++;
    21                 kValue=a[i++];
    22                 if(kIndex==k) { f=1; break; }
    23             }
    24             else
    25             {
    26                 kIndex++;
    27                 kValue=bTemp;
    28                 if(kIndex==k) f=1;
    29                 break;
    30             }
    31         }
    32         if(f==1) break;
    33     }
    34     printf("%d
    ",kValue);
    35     return 0;
    36 }
    View Code

    算法二:时间复杂度O(log(n+m))。当然,假如考虑输入,那时间复杂度仍然是O(n+m)

    代码来源:http://www.cnblogs.com/swanspouse/p/5285015.html

    代码解析:

    • 传统解法,最直观的解法是O(m+n)。直接merge两个数组,然后求第K大的数字。

    • 如果想要时间复杂度将为O(log(m+n))。我们可以考虑从K入手。如果我们每次能够删除一个一定在第K个元素之前的元素,那么我们需要进行K次,但是如果每次我们都删除一半呢?由于两个数组都是有序的,我们应该充分利用这个信息。

      • 假设A B 两数组的元素都大于K/2,我们将A B两数组的第K/2个元素进行比较。比较的结果有三种情况。
        • A[K/2] == B[K/2]
        • A[K/2] > B[K/2]
        • A[K/2] <= B[K/2]
      • 如果 A[K/2] < B[K/2] 意味着 A[0] 到 A[K/2] 肯定在A∪B的前k个元素中。因此我们可以放心删除A数组的这个k/2个元素。同理A[K/2] > B[K/2]。
      • 如果 A[K/2] == B[K/2] 说明已经找到了第K个元素,直接返回A[K/2]或者B[K/2]。
     1 #include <stdio.h>
     2 #include <iostream>
     3 using namespace std;
     4 int a[1000005],b[1000005];
     5 int find_kth(int A[],int m, int B[], int n, int k)
     6 {
     7     if(m > n )  return find_kth(B, n, A, m, k);
     8     if( m == 0) return B[k-1];
     9     if( k == 1) return min(A[0], B[0]);
    10 
    11     int ia = min(k /2, m);
    12     int ib = k -ia;
    13     if( A[ia-1] < B[ib -1]) 
    14         return find_kth(A +ia, m -ia, B, n, k -ia);
    15     else if( A[ia-1] > B[ib-1])
    16         return find_kth(A, m, B +ib, n -ib, k -ib);
    17     else
    18         return A[ia-1];
    19 }
    20 int main(int argc, char *argv[])
    21 {
    22     int i,n,m,k;
    23     int ans;
    24     scanf("%d%d%d",&n,&m,&k);
    25     for(i=0;i<n;i++) scanf("%d",&a[i]);
    26     for(i=0;i<m;i++) scanf("%d",&b[i]);
    27     ans=find_kth(a,n,b,m,k);
    28     printf("%d
    ",ans);
    29     return 0;
    30 }

    说明

    • 注意其中的递归终止条件。
    • 将求第K大元素的问题划分成为子问题,不断的对问题进行缩小,采取递归的方式求解。
    • 此问题可以进行拓展,比如求两有序数组的中位数。
  • 相关阅读:
    c程序设计语言_习题1-16_自己编写getline()函数,接收整行字符串,并完整输出
    c程序设计语言_习题1-13_统计输入中单词的长度,并且根据不同长度出现的次数绘制相应的直方图
    c程序设计语言_习题1-11_学习单元测试,自己生成测试输入文件
    c程序设计语言_习题1-9_将输入流复制到输出流,并将多个空格过滤成一个空格
    c语言时间库函数#include<time.h>
    c语言输入与输出库函数#include<stdio.h>
    c语言诊断_断言库函数#include<assert.h>
    c语言实用功能库函数#include<stdlib.h>
    Remove Duplicates from Sorted List
    Merge Sorted Array
  • 原文地址:https://www.cnblogs.com/huashanqingzhu/p/7325471.html
Copyright © 2011-2022 走看看