zoukankan      html  css  js  c++  java
  • 算法导论 Exercises 9.37

    Problem Description:

    Describe an O(n)-time algorithm that, given a set of S of n distinct numbers and a positive integerd k ≤ n,

    determines the k numbers in S that are closest to the median of S.

    问题描述:

    有一个长为n的数组且数组元素互不相同,要求以O(n)的时间复杂度找到离数组中值最近(与中值的差的绝对值最小)的k个数(k ≤ n)。

    问题升级:

    题目要求是找离中值最近的 k 个数,这里做一下推广,找离数组中第 i 个数最近的k个数。原题作为 i = n / 2 + n % 2; 时的特殊情况。

     

    解决方案:

    1、首先,找数组的第 i 小的数是O(n)的(参见 ithSmallestLinear )。

    2、假设数组中第 i - k 小的数是 m ,第 i + k 小的数是 n ,则离数组第 i 个数最近的 k 个数一定在[m, n]这个大小范围内。

    3、把原数组中上述范围内的数放到数组最前面,然后求这些数离第 i 个数的距离,并找到第 k 小的距离 distThreshold。

    4、用这个阈值再扫描一遍原数组即可得到离第 i 个数最近的 k 个数。

    需要注意的是:

    由于原数组的元素是互不相同的,则满足离第 i 个数距离为distThreshold的数的个数只可能为 k 或者 k + 1。

    因为存在这样一种情况:2 5 8 中 2 和 8 离 5 的距离相同都为 3,但不可能在原数组中找到第三个数离 5 的距离为 3。

    因此在第四步扫描原数组找最近的 k 个数的时候要处理一下这种情况。

     

    实现代码:

    View Code
     1 View Code 
     2  void selectKClosestNumbers(int a[], int beg, int end, int i, int k)
     3  {
     4      if (k > end - beg)
     5      {
     6          return;
     7      }
     8  
     9      int ivalue = a[ithSmallestLinear(a, beg, end, i)];
    10      int lowerBoundSeqNum = (i - k < 1) ? 1 : i - k;
    11      int upperBoundSeqNum = (i + k > end - beg + 1) ? end - beg + 1 : i + k;
    12      int lowerBound = a[ithSmallestLinear(a, beg, end, lowerBoundSeqNum)];
    13      int upperBound = a[ithSmallestLinear(a, beg, end, upperBoundSeqNum)];      
    14      
    15      int count = 0;
    16      //search elements in the range of [lowerbound, upperbound], at most 2k
    17      for (int j = 0; (count != 2 * k) && (j != end); ++j)
    18      {
    19          if ((a[j] >= lowerBound) && (a[j] <= upperBound) && (a[j] != ivalue))
    20          {
    21              swap(a, j, count++);
    22          }
    23      }
    24      int *dist = new int[count];
    25      //calculate the distance to the ivalue
    26      for (int j = 0; j != count; ++j)
    27      {
    28          dist[j] = abs(a[j] - ivalue);
    29      }
    30      int threshold = dist[ithSmallestLinear(dist, 0, count - 1, k)];
    31      //the number of candidate whose distance to the ivalue <= threshold
    32      //candidateNum == k or k+1
    33      int candidateNum = 0;
    34      for (int j = 0; j != count; ++j)
    35      {
    36          if (dist[j] <= threshold)
    37          {
    38              ++candidateNum;
    39          }
    40      }
    41  
    42      //select k elements
    43      for (int j = 0, t = 0; t != k; ++j)
    44      {
    45          int tmpDist = abs(a[j] - ivalue);
    46          if (tmpDist < threshold)
    47          {
    48              swap(a, j, t++);
    49          }
    50          //select the second candidate once there are two candidiates 
    51          //whose distance to the ivalue equal threshold
    52          if ((tmpDist == threshold) && (candidateNum-- != k + 1))
    53          {
    54              swap(a, j, t++);
    55          }
    56      }
    57  
    58      delete [] dist;
    59  }

    测试:

    取数组元素为 1 2 3 4 5 6 7 8 9 10

    ①找与第6个数(6)最近的5个数,这里dist的阈值是3,而4和9同时满足这个阈值,按照实现代码里的逻辑,我们取排在后面的9。

    ②找与第1个数(1)最近的3个数,这种情况下没有比1小的数,所以这3个数应该是2 3 4。

    测试代码:

    View Code
     1 int main(void)
     2 {
     3     int testArrayA[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
     4     int testArrayB[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
     5 
     6     selectKClosestNumbers(testArrayA, 0, 9, 6, 5);
     7     selectKClosestNumbers(testArrayB, 0, 9, 1, 3);
     8 
     9     outputArray(std::cout, testArrayA, 0, 4);
    10     outputArray(std::cout, testArrayB, 0, 2);
    11 
    12     return 0;
    13 }

     

    文中一些自定义函数的实现见文章“#include”

  • 相关阅读:
    Python 模块 itertools
    Python 字符串的encode与decode
    python 模块 hashlib(提供多个不同的加密算法)
    暴力尝试安卓gesture.key
    hdu 1300 Pearls(DP)
    hdu 1232 畅通工程(并查集)
    hdu 1856 More is better(并查集)
    hdu 1198 Farm Irrigation(并查集)
    hdu 3635 Dragon Balls(并查集)
    hdu 3038 How Many Answers Are Wrong(并查集)
  • 原文地址:https://www.cnblogs.com/snser/p/2746973.html
Copyright © 2011-2022 走看看