从整数范围内搜索

Posted

技术标签:

【中文标题】从整数范围内搜索【英文标题】:Search from a range of integers 【发布时间】:2012-09-26 03:46:18 【问题描述】:

我需要从整数列表中查找一个整数。我对它们进行排序并使用 lower_bound 来查找给定整数的范围。这需要 O(lgn)。有没有比这更好的方法?

以下是改进的提示。

    给定的列表总是正整数 列表已修复。没有插入或删除。

一种方法是创建一个数组并索引到数组中。这可能不节省空间。 我可以使用 unordered_map 吗?我应该定义什么哈希函数?

// Sort in reverse order to aid the lookup process
vector<unsigned int> sortedByRange;
//... sortedByRange.push_back(..)
sort(sortedByRange.begin(), sortedByRange.end(), greater);
Range = (sortedByAddress_.begin() - sortedByRange.end();
std::cout<<"Range :"<<Range<<std::endl;    //prints 3330203948

std::pair<unsigned int, unsigned int> lookup(unsigned int addr)
    pair<unsigned int, unsigned int> result;
    vector<unsigned int>::iterator it = lower_bound(sortedByRange.begin(), 
                                           sortedByRange.end(), addr);
    result.first = *it;
    result.second = *(it++);
    return result;
      

【问题讨论】:

没有代码 - 没有答案 - 先尝试一下 @AdrianCornish:这更多是算法问题。我认为 OP 已经提到了 lower_bound。 我不在乎 - 显示代码或没有答案,这看起来很像我看到的 100,000 个作业问题,您希望其他人为您做作业。试过什么代码,计时结果如何…… 我可以使用 unordered_map 吗?当然。我应该定义什么哈希函数?什么工作最快取决于输入和 # 桶 - 例如,如果它们是有效的随机数或递增数字,您可以直接使用它们。如果# buckets 是素数,并且这些数字并非全部从素数的倍数病理上偏移,那么您也可以使用这些数字。如果你想要一些通用的东西,然后谷歌搜索一个强大的哈希函数。如果您需要通常足够好,请使用 boost::hash 或让 unordered_map 使用其默认值。 @nhahtdh 然后显示你尝试过的代码,作业与否,你的实际结果是什么 - 先尝试一下 - 不要要求为你完成工作 【参考方案1】:

如果总范围不是很大,您可以构建一个任何方便大小的采样索引数组(您想投入多少 RAM?)

因此,例如,如果数据的总范围是 256M,并且您有一个空闲的兆字节,那么您存储数据范围的每 1K 间隔的位置。然后对于任何给定的数据点,你做一个 O(1) (实际上是 O(2) :) )探测索引数组以找到该数据点的最低和最高合理范围,然后你可以做最低限度范围。如果您的范围在大小上没有太大变化,那应该会给您平均恒定时间查找。

如果您不想在问题上投入太多内存,可以尝试基于平均范围大小和模糊因子的一对线性估计。如果结果不包含特定数据点,则可以回退到完整的二进制搜索;否则,同样,限制范围内的二进制搜索应该是平均线性时间。

这是第一个建议,以防挥手不够清晰。完全未经测试的代码,甚至没有尝试编译它,并且至少可以说整数类型的使用是草率的。如果你使用它,试着让它更漂亮。我也应该(但没有)将索引范围的开始限制为 *begin_;如果显着大于 0,则应该修复它。

// The provided range must be sorted, and value_type must be arithmetic.
template<type RandomIterator, unsigned long size>
class IndexedLookup 
 public:
  using value_type = typename RandomIterator::value_type;
  IndexedLookup(RandomIterator begin, RandomIterator end)
    : begin_(begin),
      end_(end),
      delta_(*(end_ - 1) / size) 
    for (unsigned long i = 0; i < size; ++i)
      index_[i] = std::lower_bound(begin_, end_, i * delta_) - begin_;
      // The above expression cannot be out of range
    index_[size] = end_ - begin_;
  

  RandomIterator lookup(value_type needle) 
    int low = needle / delta_;
    return std::lower_bound(index_[begin_ + low],
                            index_[begin_ + low + 1],
                            needle);
  

 private:
  RandomIterator begin_, end_;
  value_type delta_;
  std::array<int, size + 1> index_;
    

【讨论】:

【参考方案2】:

方法一:如果你只需要知道给定的数字是否在列表中,并且最大值不是太大,你可以考虑使用位域。查找将是 O(1) 操作。

方法 2: 如果值的范围很大(其中有小整数和大整数),但列表大小不大(例如几千),您可以尝试(以编程方式)制作一个散列函数,

    在列表中的值上是一对一的; 将给出一个范围为0 ... N + m 的值,而m 足够小; 计算起来相对便宜。

然后可以将常量列表的值放入由哈希值索引的数组中,以便快速检查给定输入值的包含情况。如果列表中有空洞(m 非零),则应使用特殊值(例如-1)指示空洞。

包含测试:对于给定的输入 1.计算哈希值; 2.如果哈希值的值超出范围,则输入不在列表中; 3. 否则,当且仅当由哈希值索引的生成数组中的值与输入值相同时,输入才属于列表。

如何制作散列函数值得在 SO 中提出另一个问题(对于字符串值,存在为此目的生成工具的工具)。 :-)

局限: 如果列表不是在编译时创建的,而是在程序运行时计算或接收的,那么这种方法不适合。此外,如果这个列表经常变化,那么生成哈希函数和代码所需的计算时间可能会使这种方法不适合。

【讨论】:

由于不知道给定列表中的最大值,如何有效地确定位向量的大小? @Vikdor:我不知道你为什么说最大值未知,而问题清楚地说“列表是固定的”。 那么,您将遍历列表以找到导致 O(n) 的最大值,这样可以吗?明白了。 @Vikdor:但你只需要这样做一次,而不是每次查找。因此摊销成本变为 O(1)。 因为查找次数将以百万为单位。像排序这样的预处理是可以接受的【参考方案3】:

Javascript

let searchRangeInterger = function(nums, target) 
  let res = [-1, -1];
  let leftSide = find(nums, target, true);
  let rightSide = find(nums, target, false);
  if (!nums.length) return res;
  if (leftSide > rightSide) return res;
  return [leftSide, rightSide];
;

let find = function (nums, target, findLeft) 
  var left = 0;
  var right = nums.length - 1;
  var mid = 0;

  while (left <= right) 
    mid = Math.floor((left + right) / 2);
    if (nums[mid] > target || (findLeft && nums[mid] === target)) 
      right = mid - 1;
     else 
      left = mid + 1;
    
  

  return findLeft ? left : right;
;

【讨论】:

以上是关于从整数范围内搜索的主要内容,如果未能解决你的问题,请参考以下文章

搜索之双向搜索

lucene-查询query->RangeQuery在某一范围内搜索

intelliJ -> 有啥方法可以将您的搜索范围限定在一个函数内

优化 MySQL 查询以进行整数范围搜索

如何在多个时间范围内搜索烛台形态

从 iPhone 应用程序搜索和连接蓝牙设备