【问题标题】:Recursive algorithm problem(missing number)递归算法问题(缺数)
【发布时间】:2021-10-14 18:38:30
【问题描述】:

所以我有一个数组 A[1:n],其中包含从 1 到 n+1(包括 n+1)的随机唯一数。任务是找到丢失的号码。通常你只需创建一个额外的数组 B[1:n+1] 并将数组 A 中的每个当前数字标记为数组 B 中的 1。 但是在这个问题中,数组 A 中的每个数字都以二进制代码作为字符串给出,我只能通过第 i 个字符串中的第 j 个符号访问 A 的元素 目标是想出一个复杂度为O(n)的算法

我的想法: 我想出了一个基于合并排序的算法,它会根据二进制代码中的第一个数字对每个字符串进行排序。但是复杂度是O(nlgn)

【问题讨论】:

  • 请发布您编写的一些代码,以及输入和预期输出。
  • 数组 A[1:n] 有 n 个元素,但 0 到 n + 1 有 n + 2 个数字。将缺少 2 个号码。
  • 另外,我不太明白在“二进制代码”中作为字符串给出的意思。前导零是否存在?二进制代码作为字符串的确切格式是什么?为什么不能将“二进制字符串”转换回数组 B 中的位置,因为它仍然是 O(n)
  • @AnsonYeung 我也是这么想的,然后将值相加并从 (n+1)*(n+2)/2 中减去。
  • @Vincent van der Weele 我想我得到了提示,我可以创建一个数组 L 将包含所有第一位小于数字 n//2 的数字和一个数组 R 将包含所有第一位大于数字 n//2 的数字。如果 R 的元素多于 L,则缺失的数字将大于 n//2,否则将小于 n//2。此外,我将使用长度更大的数组继续该过程。总之,时间的递归公式将是 t(n) = t(n/2) + n 或 t(n) = O(n) 我有正确的想法吗?

标签: arrays algorithm recursion time-complexity


【解决方案1】:

正如 cmets 中所讨论的,如果 A 的元素只能逐位访问,则不可能有 O(n) 解决方案,因为必须读取所有位,并且有 log n每个数字中的位。可以做到的最好是O(n log n)

也就是说,如果数组包含从 1 到 n+1 范围内的 n 元素,并且恰好缺少一个值,则可以通过将数组的总和与 @ 的总和进行比较来找到缺失的值987654328@,由标准formula(n+1)(n+2)/2给出。

int n = 3;
String[] arr = {"001", "010", "100"};

int sum = 0;
for(int i=0; i<arr.length; i++) 
    for(int j=0, v=1; j<arr[i].length(); j++, v*=2)
        if(arr[i].charAt(j) == '1') sum += v;

int m = (n+1)*(n+2)/2 - sum;

System.out.println("Missing: " + m);

输出:

Missing: 3

【讨论】:

  • 感谢@pjs 指出我的原始答案遗漏了有关数字被表示为二进制字符串的细节。
  • 这看起来像 Java(给定 System.out.println),在这种情况下,我将注释掉手动转换(将其留在那里以显示正在完成的概念工作)并使用 Integer' s parseUnsignedInt(String s, int radix) 实际进行转换。
【解决方案2】:

这是一个在 Ruby 中使用内置二进制转换的工作实现。我已经对它进行了足够多的评论,以至于我认为不需要额外的措辞来解释。请注意,此操作不需要对二进制字符串进行排序。

ary = ["1", "010", "100", "110", "11"]  # Works with or without leading zeros
n_plus_1 = ary.size + 1
result = n_plus_1 * (n_plus_1 + 1) / 2  # Total if all values were present

# Convert each string in ary to int using base 2, and deduct from the total
ary.each { |str| result -= str.to_i(2) }

# The remainder is the missing value
puts "Missing value is #{result} (binary #{result.to_s(2)})"

它和下面的代码都会产生以下输出:

缺失值为 5(二进制 101)

如果你想避免内置转换,这里有一个递归转换器,它应该可以直接翻译成其他语言。请注意,给定默认值的 Ruby 方法参数不需要在方法调用中显式提供:

def str_to_i(char_ary, power = 1, radix = 2)
  return 0 if char_ary.size == 0  # Base case
  bit = char_ary.pop.to_i  # Remove last character in array and convert to int
  return bit * power + str_to_i(char_ary, power * radix, radix)
end

ary = ["1", "010", "100", "110", "11"]  # Works with or without leading zeros
n_plus_1 = ary.size + 1
result = n_plus_1 * (n_plus_1 + 1) / 2  # Total if all values were present

# Convert each string to array of chars, then to int, and deduct from total
ary.each { |str| result -= str_to_i(str.chars) }

# The remainder is the missing value
puts "Missing value is #{result} (binary #{result.to_s(2)})"

这也满足了您对recursion 标签的使用。

如果你想在递归上做完整的 Monty:

def str_to_i(char_ary, power = 1, radix = 2)
  return 0 if char_ary.size == 0  # Base case
  bit = char_ary.pop.to_i  # Remove last character in array and convert to int
  return bit * power + str_to_i(char_ary, power * radix, radix)
end

# Assuming String -> Integer can be considered O(1):
#   T(n) = 2 * T(n/2) + O(1) => O(n)
# Stack size is O(log n), which should avoid stack overflow, where splitting
# array into subsets of 1 an n-1 would exceed recursive stack limits even for
# relatively small arrays (more than a few hundred).
def sum_array(ary, first = 0, last = ary.size - 1)
  # return ary[first].to_i(2) if last == first  # using built-in conversion
  return str_to_i(ary[first].chars) if last == first  # avoiding built-in
  mid = first + (last - first) / 2
  return sum_array(ary, first, mid) + sum_array(ary, mid + 1, last)
end

ary = ["1", "010", "100", "110", "11"]  # Works with or without leading zeros
n_plus_1 = ary.size + 1
result = n_plus_1 * (n_plus_1 + 1) / 2 - sum_array(ary)    

# The remainder is the missing value
puts "Missing value is #{result} (binary #{result.to_s(2)})"

【讨论】:

    【解决方案3】:

    你可以利用这个事实

    XOR({1,..,4n-1})=0
    

    因此,如果缺少其中一个元素,XOR({1,..,4n-1}-{k})=k

    通过向给定数组添加任何必要的虚拟元素。

    【讨论】:

      猜你喜欢
      • 2012-12-25
      • 1970-01-01
      • 2017-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多