【问题标题】:What is the fast way of getting an index of an element in an array? [duplicate]获取数组中元素索引的快速方法是什么? [复制]
【发布时间】:2011-03-30 20:29:48
【问题描述】:

我在一次采访中被问到这个问题。虽然面试的是网点职位,但他还是在java的上下文中问了我这个问题,因为我在简历中也提到了java。

如何在数组中找到值为 X 的元素的索引?

我说过从第一个元素迭代到最后一个元素并检查值是否为 X 会给出结果。他询问了一种涉及较少迭代次数的方法,我说使用二进制搜索,但这仅适用于排序数组。我试着在 Array 类中使​​用 IndexOf 函数。但是我这边没有回答这个问题。

有什么快速的方法可以获取数组中值为 X 的元素的索引吗?

【问题讨论】:

  • 听起来像是面试候选人恕我直言的错误方式
  • @Samuel_xL 为什么?这个问题有什么问题?
  • 我认为 indexOf 方法也会对 Array 进行迭代。不要认为有任何这样快速的方法。
  • 如果你能以某种方式在 java 中实现 Grover 算法,那么你可以做得更好。我猜你需要一个对底层量子计算机的 JNI 调用。不独立于平台。
  • @emory:时间旅行也很具体。

标签: c# java .net


【解决方案1】:

只要不了解数组(它是排序的?升序还是降序?等等),就没有办法在不检查每个元素的情况下找到一个元素。

另外,这正是indexOf 所做的(使用列表时)。

【讨论】:

  • "... 没有检查每一个直到你找到它。",实际上。如果您的元素是第一个元素,则无需检查数组/列表中的每个元素。
  • 对不起,我认为这很明显!任何不介意他的实现的人都不值得运行它......
  • 但这并不意味着它不能更快​​地完成,即通过并行化。
  • 并行化可能更快。如果该项目位于数组的开头附近,那么与刚开始搜索数组时相比,您将执行更多的工作来并行化任务。平行化并不是让一切变得更快的灵丹妙药,它肯定更适合大型任务,但存在开销成本,使其对小型任务的效率降低。
【解决方案2】:

如何在数组中找到值为 X 的元素的索引?

这会很快:

int getXIndex(int x){ 我的数组[0] = x; 返回0; }

【讨论】:

  • 您的函数应该接收数组作为参数。除此之外,很好的答案(这也说明了 TDD 的一种危险):)
  • 我必须开始这样写我的代码——这样可以节省很多时间。
  • @fortran,您确实意识到点赞按钮的悬停帮助说“有用”而不是“有趣”,是吗?我完全是为了幽默,但除非它带有一个实际有用的答案,否则最好留在评论中:-)
【解决方案3】:

一种更快找到它的实用方法是并行处理。

只需将数组分成 N 个部分,并将每个部分分配给一个线程,该线程遍历其部分的元素,直到找到值。 N 最好是处理器的内核数。

【讨论】:

  • 好主意。但是使用处理器的核心数量来扩展它真的有用吗? VM 不会在所有内核之间平均分配线程,还是这样?
  • java 为此提供了 ParallelArray(通用)和 ParallelLongArray(原始)。 gee.cs.oswego.edu/dl/jsr166/dist/extra166ydocs/extra166y/…indexOf 操作是使用 N 分区方案实现的。
  • @f1sh - 在实践中(在 Windows 上,我的大部分经验都在其中),当使用大小为可用内核数量的 ForkJoinPool 时,您会发现所有内核的 cpu 使用率可以接近 100%。与单线程情况相比,这还为您提供了使用更多 L1 缓存的好处,因为 L1 通常专用于每个内核/内核对。
  • 那是虚拟机的职责。一般来说,在多核 CPU 上使用多个线程应该总是比只使用一个线程快。 (这忽略了划分数组和启动线程的开销。数组当然应该足够大以证明并行化的合理性)。
  • 为了获得更高的并行性,您始终可以将工作分配给一两个 GPU:jcuda.de
【解决方案4】:

如果无法进行二分搜索(因为数组未排序)并且您没有某种高级搜索索引,那么我能想到的唯一方法不是 O(n) 是项在数组中的位置是项本身的函数(例如,如果数组是[10, 20, 30, 40],则元素n 的位置是(n / 10) - 1)。

【讨论】:

  • 让数组的值取决于它的索引是某种排序 - 至少可以很好地提示您如何排列元素。
  • 哈希表基本上是这样工作的。
【解决方案5】:

也许他想测试你对 Java 的了解。

有一个Utility Class叫做Arrays,这个类包含了各种操作数组的方法(比如排序和搜索)

http://download.oracle.com/javase/6/docs/api/java/util/Arrays.html

在 2 行中,您可以获得 O(n * log n) 的结果:

    Arrays.sort(list); //O(n * log n)
    Arrays.binarySearch(list, 88)); //O(log n)

【讨论】:

  • 在合并排序的最佳情况下,排序已经是O(n*log(n))(如果我没记错的话,那是在Java utils中实现的算法),所以你的解决方案比线性更差(O(n*log(n)^2)确实)。
  • 应该是 O(nlog n) 因为排序(假设比较模型)需要 O(nlog n) 并且二进制搜索是 O(log n) 所以总计为 O(logn + nlogn) = O(nlogn)
  • @Ahmed 你说的很对!我会更新我的评论,但版本时间已过期:-s
  • 你说得对,艾哈迈德,我只是在考虑搜索问题。我已经解决了,谢谢。
  • 这个问题是它没有按照要求给你数组中元素的位置,仅仅是因为它改变了数组的顺序! 排序后的索引和排序前的索引没有关系。
【解决方案6】:

Puneet - 在 .net 中:

string[] testArray = {"fred", "bill"};
var indexOffset = Array.IndexOf(testArray, "fred");

[edit] - 现在正确阅读了问题,:) linq 中的替代方案是:

string[] testArray = { "cat", "dog", "banana", "orange" };
int firstItem = testArray.Select((item, index) => new
{
    ItemName = item,
    Position = index

}).Where(i => i.ItemName == "banana")
  .First()
  .Position;

这当然会找到字符串的第一次出现。随后的重复将需要额外的逻辑。但循环方法也是如此。

吉姆

【讨论】:

  • Java 中不存在该方法... a) 您使用的是什么 Array 类? b) java 中的方法名不以大写字母开头
  • 您似乎没有阅读整个问题,我要求他们使用 IndexOf 函数,但他们要求我自己编写逻辑。他们说您编写的简单循环是正确的,但是可以改进并减少迭代次数。想想吧!!!
  • f1sh - 哎呀,正确并更正了...... puneet - 是的,现在可以看到了。有点赶时间!!
  • @Puneet Dudeja 很好,因为不可能在更少的迭代中做到这一点,他们希望你这么说并解释原因。要么就是这样,要么就是完全错误。
  • 这基本上是OP想要的相反(!);您只是在通过枚举(使用Where/First)有效地确定项目索引的过程中添加了更多开销(构造许多新的匿名类型对象)。跨度>
【解决方案7】:

这是一个关于数据结构和算法的问题(尽管是一个非常简单的数据结构)。它超越了您使用的语言。

如果数组是有序的,你可以使用二分搜索得到 O(log n) 和边界情况的修改版本(不总是使用 (a+b)/2 作为枢轴点,但这是一个非常复杂的怪癖)。

如果数组没有排序,那么……祝你好运。

他可能会询问您有哪些方法可以在 Java 中查找项目。但无论如何,它们并没有更快。它们可以更简单地使用(比 for-each - compare - return)。

还有另一种解决方案是创建一个辅助结构来进行更快的搜索(如哈希图),但当然,创建它并使用它一次比进行简单的线性搜索更昂贵。

【讨论】:

  • 我认为您的意思是 O(log n) 用于有序数组。
【解决方案8】:

获取一个完全未排序的数组,只是内存中的数字列表。机器所能做的就是查看内存中的单个数字,并检查它们是否是正确的数字。这就是“密码破解问题”。没有比从头开始搜索直到找到正确值更快的方法了。

【讨论】:

    【解决方案9】:

    你确定这个问题吗?我有一个与您的问题有些相似的问题。

    给定一个排序数组,有一个元素“x”,其值与其索引相同,找到该元素的索引。

    例如:

             //0,1,2,3,4,5,6,7,8,9, 10     
    int a[10]={1,3,5,5,6,6,6,8,9,10,11};
    

    在索引 6 处,值和索引相同。

    对于这个数组 a,答案应该是 6。

    这不是答案,如果原始问题中遗漏了什么,这将澄清这一点。

    【讨论】:

    • 您的问题的正确答案是什么?有没有办法做到这一点
    • 据我记得,问题是我在这里问的,因为我在回复之前确认了2-3次。
    【解决方案10】:

    如果您拥有的唯一信息是它是一个未排序的数组,索引和值之间没有关系,并且没有辅助数据结构,那么您可能需要检查 每个元素,看看它是否包含你想要的信息。

    不过,面试的目的是将小麦与谷壳分开,因此重要的是要意识到他们希望了解您如何解决问题。因此,我们的想法是提出问题,看看是否有更多信息(或可以提供),这些信息可以使您的搜索更有效率。

    类似的问题:


    1/ 数据是否经常变化?

    如果没有,那么您可以使用额外的数据结构。

    例如,维护一个最初为 true 的 dirty 标志。当你想找到一个项目并且它是真的时,构建一个额外的结构(排序数组、树、散列或其他),这将大大加快搜索速度,然后将 dirty 标志设置为 false,然后使用该结构来查找项目.

    如果你想找到一个项目并且dirty标志是假的,只需使用结构,不需要重建它。

    当然,对数据的任何更改都应将 dirty 标志设置为 true,以便下一次搜索重建结构。

    这将大大加快(通过摊销)对读取频率远高于写入频率的数据的查询。

    换句话说,更改后的第一次搜索会相对较慢,但后续搜索会快得多。

    您可能希望将数组包装在一个类中,以便正确控制dirty 标志。


    2/ 我们是否允许使用与原始数组不同的数据结构?

    这将与上面给出的第一点相似。如果我们将数据结构从数组修改为任意类包含该数组,您仍然可以获得所有优点,例如快速随机访问每个元素。

    但我们获得在数据发生变化时更新数据结构中的额外信息的能力。

    因此,与其使用dirty 标志并在下次搜索时进行large 更新,我们可以在数组为改变了。

    这通过在所有更改中摊销成本(每个更改的成本很小)来消除更改后第一次搜索的缓慢响应。


    3.列表中通常会有多少项?

    这实际上比大多数人意识到的更重要。

    除非您的数据集相对较大并且性能实际上很重要,否则所有关于优化的讨论往往都是无用的。

    例如,如果您有一个 100 项的数组,那么即使使用脑死亡冒泡排序也是完全可以接受的,因为它与您能找到的最快排序之间的时间差异往往是无关紧要的(除非您需要当然每秒执行数千次)。

    对于这种情况,查找给定值的第一个索引,只要您的数组保持在特定大小以下,进行顺序搜索可能是完全可以接受的。


    最重要的是,您在那里证明自己的价值,而面试官(通常)在那里为您提供指导。除非他们是虐待狂,否则他们很乐意你向他们提问以缩小问题的范围。

    提出问题(因为您有可能对数据进行排序。即使您无法提出一个解决方案。

    事实上(我过去也这样做过),他们可能会拒绝你所有可能的方法(不,它没有排序,不,不允许其他数据结构,等等)只是为了看看你能走多远得到。

    也许,只是也许,就像小林丸,它可能不是关于胜利,它可能是你如何处理失败:-)

    【讨论】:

      猜你喜欢
      • 2013-06-02
      • 1970-01-01
      • 2016-01-14
      • 2019-12-25
      • 1970-01-01
      • 2012-09-28
      • 2018-07-01
      • 2016-05-13
      • 1970-01-01
      相关资源
      最近更新 更多