【问题标题】:Count numbers with same digits in a sorted int array in O(log n) time在 O(log n) 时间内计算排序 int 数组中具有相同数字的数字
【发布时间】:2019-04-29 16:39:07
【问题描述】:

我遇到了一个面试问题,要求应聘者用相同的数字计算数组中的所有数字。 例如:

用 int input = 394 计算所有数字相同的数字 int[] arr = {1, 14, 101, 349, 439, 745, 934}

该函数将返回 3,因为 439、934、349 共享相同的数字。 问题是如何在 O(log n) 时间内解决这个问题?我还是大 O 概念的新手,除了 O(n) 和 O(n^2)...我无法理解如何归档 O(log n)。

我的第一个想法是: 我会计算数组中所有元素的数字总和。如果总和相等,则它们包含与输入数字相同的数字。

      int counter = 0;

      while (num > 0) {
         int digitSum += num % 10;
         num = num / 10;
      }
      for(int i = 0; i < arr.length; i++) {
      int k = arr[i];

      while (k > 0) {
          int sumOfDigits += k % 10;
          k = k/10;
      }
      if(sumOfDigits == digitSum) {
       counter++;
      }
}

我知道这至少需要 O(n) 时间,但我很难找到更好的解决方案。

【问题讨论】:

  • 你怎么能数出事物的数量而不数所有的事物呢?如果您可以预处理,您将能够知道一些您可以跳过的东西;但您仍然需要对所有内容进行预处理。
  • 我想你可以置换输入的数字(394、349、934、943、439、493),然后在数组中搜索所有这些数字。
  • 为了扩展安迪的评论,对于每个数字排列,您使用二进制搜索来查找数组中数字的索引。如果找到了,则在索引的左侧和右侧计算相同的数字。
  • 如果总和相等,则它们包含与输入数字相同的数字。 - 295 怎么样?
  • 我看不出你怎么能在 log n 时间内做到这一点。如果整个列表有效怎么办。您需要查看每个值。你能做的最好的就是线性

标签: java arrays algorithm time-complexity big-o


【解决方案1】:

Andy Turner 和 JB Nizet 给出了最佳答案,但遗憾的是仅作为评论:

为此,我们必须假设:输入数字的大小是有界的,数组中的整数是不相交的,n 是数组中元素的数量。

  1. 计算输入数字的所有排列。如果数字有重复的数字,某些排列可能是相同的,只取一次。这需要 O(1) 时间,排列次数也是 O(1)。
  2. 对于每个排列,使用二进制搜索在数组中查找相应的数字并计算所有命中。这需要 O(log n)。

总共可以获得 O(log n) 的运行时间。

请注意,这仅在输入数字的界限相当低时才实用。如果输入的数字可以说是 20 位,那么使用 O(n) 方法会更好,除非 n 真的很大。

【讨论】:

  • 谢谢!我一定会尝试你的解决方案
  • 这假定数组按排序顺序出现。如果我在采访中问,我肯定有一个未排序的数组。此外,即使使用 10 位数字,您也需要进行数百万次查找。
  • @btilly 如果数组未排序,您建议怎么做?哦,是的,你是对的,如果输入比数组长或者数组只包含输入的单个排列怎么办..
  • @BCuracao 查看我建议的答案。对我来说,这种方法对于欧拉计划的许多问题都很有效。
  • @btilly 很明显,由于常数很大,这种算法在大多数情况下并不实用。但问题是要找到一个 O(log n) 算法,这显然是。在大多数情况下,您的方法会快得多,但时间复杂度为 O(n) 甚至 O(n log n),具体取决于地图实现。
【解决方案2】:

您可以对数组进行预处理以构造一个映射,方法是通过映射到该规范化表示的数组中数字的“表示排序数字的字符串”。在该步骤之后,根据选择的映射,单个查找为 O(1)O(log(n))。匹配多少个数字都无关紧要,因为您只是返回一个预先构造的数组。

所以查找确实可以非常快。但前提是您要么打折预处理步骤,要么将其分摊到多次查找中。

【讨论】:

  • 感谢您的提示!
  • “构造一个映射,通过映射到该规范化表示的数组中的数字的“表示排序数字的字符串”到底是什么意思?我不明白对不起。你有例子吗?
  • @BCuracao 假设您有一个函数normalize(n),它接受一个数字n,如2018,并返回一个排序后的数字字符串,如'0128'。然后你会想要一个HashMap,它的键是 normalize 返回的字符串,它的值是映射到该字符串的所有数字的数组。打电话给lookup。那么lookup.get(normalize(n)) 就是你的答案。
【解决方案3】:

这个解决方案几乎是 O(n),因为与给定的数组大小 (n) 相比,输入中的位数非常小。

想法是从每个元素中获取最小可能的数字,并与输入数字的对应值进行比较

public static void main(String []args){

    int input = 394;
    int[] arr = {1, 14, 101, 349, 439, 745, 934};


    int ans = 0;
    int hold = getMin(input);
    for(int i = 0; i < arr.length; i++)
    {
        if(hold == getMin( arr[i] ))
        {
            ans++;
        }
    }
    System.out.println(ans);
}

public static int getMin(int n)
{
    int hold[] = new int[10];
    while( n > 0)
    {
        hold[n % 10]++;
        n /= 10;
    }

    int ans = 0;
    for(int i = 0; i < hold.length; i++)
    {
        while(hold[i] > 0)
        {
            ans = ans * 10 + i;
            hold[i]--;
        }
    }
    return ans;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-19
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    相关资源
    最近更新 更多