-1

问题说明

给定一个整数数组,找到任意两个元素之间的绝对差小于或等于 1 的最长子数组。

示例 a = [1,1,2,2,4,4,5,5,5] 有两个子数组满足条件:[1,1,2,2] 和 [4,4,5,5,5 ]。最大长度子数组有 5 个元素。

PickNumbers 具有以下参数:

  • int a[n]:整数数组

退货

  • int:满足条件的最长子数组的长度

我试过的

def pickingNumbers(a)
    # Write your code here
    a.sort!
    current_counter = 0
    max_counter = 0
    
    i = 0
    while i < a.size
      j = 1
      
      while (a[j].to_int - a[i].to_int) <= 1
        current_counter += 1
        j += 1
        max_counter = current_counter if current_counter > max_counter
      end
      
      i+=1
    end
    max_counter
end

input = [1,1,2,2,4,4,5,5,5]
pickingNumbers(input)

要求:

为什么上面的代码不起作用?如果有人可以解释,我将不胜感激。我正在学习解决算法挑战,我知道有很多更好的解决方案。不过,我想知道为什么这段代码不起作用!))提前致谢

4

4 回答 4

2

您正在检查以确保i < a.size,但您没有对j.

最终,您将 j 增加到超出数组的大小并尝试访问a[9]返回 nil 的值。

nil.to_int导致错误(尽管您实际上并未说明您在问题中看到的错误)。

在 Ruby 中遍历数组的更惯用.each的方法是使用它来避免此类错误。

我还建议不要.sort!在您传入的参数上使用。最后的!bang 运算符警告您这正在修改原始数组。

于 2021-02-18T10:04:11.190 回答
0

这是用更多时间复杂度来解决它的方法,避免使用 2 个循环

我知道可以进行的修改很少(例如使用三元运算符等)。如果您有心,欢迎您巩固

def pickingNumbers(a)
    # Write your code here
    a.sort!
    current_counter = 1
    max_counter = 0
    reference_checker = a[0]
    
    i = 1
    while i < a.size
    
      if (a[i] - reference_checker) <= 1
        current_counter += 1
      else
        reference_checker = a[i]
        max_counter = current_counter if current_counter > max_counter
        current_counter = 1
      end
      
      i+=1
    end
    if current_counter < max_counter
      max_counter
    else
      current_counter
    end
end

input = [1,1,2,2,4,4,5,5,5]
p pickingNumbers(input)

感谢我的站立团队)

于 2021-02-19T07:59:51.913 回答
0

这里有两种解决问题的方法,一种易于编码,另一种更复杂,但我希望它应该更快,可能更快。两者都使用以下数组进行演示。

a1 = [1,1,2,3,4]
a2 = [1,1,2,2,4,4,5,5,5]
a3 = [1,1,3,2,4,4,5,5,7,6,5,6,5,4,3,4,5,7,8]

代码不多,但可能足够快

def quick_n_dirty(arr)
  arr.size.downto(1).each do |n|
    arr.each_index.each_cons(n) do |a|
      mn, mx = a.map { |i| arr[i] }.minmax
      return { start: a.first, end: a.last } if mx <= mn + 1
    end
  end
end
quick_n_dirty(a1)
  #=> {:start=>0, :end=>2}
quick_n_dirty(a2)
  #=> {:start=>4, :end=>8}
quick_n_dirty(a3)
  #=> {:start=>4, :end=>7}

请参阅Enumerable#each_cons

考虑a1,它包含五个元素。先看看整个数组是否满足要求,这样我们就完蛋了:

enum = a1.each_cons(5)
  #=> #<Enumerator: [1, 1, 2, 3, 4]:each_cons(5)>

要查看将生成的元素,enum我们可以将其转换为数组:

enum.to_a
  #=> [[1, 1, 2, 3, 4]]

它本身只生成一个元素a1

a = enum.next
  #=> [1, 1, 2, 3, 4]
b, c = a.minmax 
  #=> [1, 4]

正如我们看到的那样,(c-b).abs = 3不符合要求。现在考虑所有大小为 的子数组。如果发现一个具有所需的属性,我们就完成了。3 > 1a14

enum = a1.each_cons(4)
  #=> #<Enumerator: [1, 1, 2, 3, 4]:each_cons(4)>
enum.to_a
  #=> [[1, 1, 2, 3], [1, 2, 3, 4]]
a = enum.map { |arr| arr.minmax }
  #=> [[1, 3], [1, 4]]
b = a.map { |x,y| (y-x).abs }
  #=> [2, 3]
b.find { |diff| diff <= 1 }
   #=> nil

这告诉我们没有4满足要求的大小子数组,因此我们继续查看大小子数组3

enum = a1.each_cons(3)
  #=> #<Enumerator: [1, 1, 2, 3, 4]:each_cons(3)>
enum.to_a
  #=> [1, 1, 2], [1, 2, 3], [2, 3, 4]]
a = enum.map { |arr| arr.minmax }
  #=> [[1, 2], [1, 3], [2, 4]]
b = a.map { |x,y| (y-x).abs }
  #=> [1, 2, 2]
b.find { |diff| diff <= 1 }
  #=> 1

支付污垢!我们发现子数组[1, 1, 2]符合要求,所以我们完成了!

这就是我的代码所做的,除了它返回一个散列,显示具有所需属性的最大子数组(或者我应该说“a”,而不是“the”,因为可能存在关联)的开头和结尾。(在重新阅读问题时,似乎只需要最大子数组的长度,允许进行小幅简化。)

如果n = arr.size,在最坏的情况下,必须检查的子数组的数量等于n + (n-1) + (n-2) + ... + 2 + 1,等于n*(n+1)/2

更多代码,但应该更快

def should_be_faster(arr)
  a = arr + [Float::INFINITY]
  current = { early: 0, late: nil }
  a.each_with_index.with_object({ start: 0, end: 0 }) do |(n,i), longest|
    next if i.zero?               
    curr_val = a[i]
    curr_early_val = a[current[:early]]
    curr_late_val = current[:late].nil? ? nil : a[current[:late]]
    if current[:late].nil?
      case curr_val - curr_early_val
      when 0
      when 1, -1
        current[:late] = i
      else
        update_if_improvement(current, longest, i)
        current[:early] = i
        current[:late] = nil
      end
    elsif curr_val != curr_early_val && curr_val != curr_late_val
      update_if_improvement(current, longest, i)
      if (curr_val - curr_late_val).abs == 1
        current[:early] = current[:late]
        current[:late] = i
      else
        current[:early] = i
        current[:late] = nil
      end
    end
  end
end
def update_if_improvement(current, longest, i)
  if i - current[:early] > longest[:end] - longest[:start] + 1
    longest[:start] = current[:early]
    longest[:end] = i-1
  end
end
should_be_faster(a1)
  #=> {:start=>0, :end=>2}
should_be_faster(a2)
  #=> {:start=>4, :end=>8}
should_be_faster(a3)
  #=> {:start=>4, :end=>7}
于 2021-02-19T08:38:58.927 回答
-1

我有一个例程将数组分成组,因此 [1,1,1,2,2,2,3,3,3] 将是 2 个数组 [1,1,1,2,2,2]和 [3,3,3]

显然,如果这是为了hackerrank,你需要看看它是否足够快。

如果你想要一个糟糕的单班轮:

a.sort.inject({}) {|x,y| x.key?(y-1) ? x[y-1] << y : (x[y]||=[] ; x[y] << y) ; x}.values.map(&:count).max

或作为更长的程序:

def pickingNumbers(a)
  # sort the array and work through the array with an accumulator
  newh = a.sort.each_with_object({}) do |value, acc|
    # check if we had a previous value
    if acc.key?(value - 1)
      # push the current value into the array for the previous value
      acc[value - 1] << value
    else
      # make sure that the "acc[value]" is an array
      acc[value] ||= []
      # push the current value into the value for the current value
      acc[value] << value
    end
  end

  # get the size of all of the values in the newly created hash
  vals = newh.values.map(&:count)

  # return the maximum of that array
  vals.max
end

input = [1,1,2,2,4,4,5,5,5]
pickingNumbers(input)
于 2021-02-18T12:41:50.727 回答