查找具有相同数字的下一个最小数字

时间:2019-07-10 14:14:36

标签: ruby

我正在与Ruby一起工作,并试图编写将接受数字输入并返回具有相同数字的下一个最大数字的代码。

我以前在这里看到过同样的问题,但是代码相差太大,无法帮助我解决自己的特殊问题。

def next_smaller n
  ndigitsarray=n.digits.reverse
  bigdigitsarray=ndigitsarray.sort.reverse
  bigdigitsjoint=bigdigitsarray.join.to_i
    while bigdigitsjoint>n do 
  bigdigitsarray.insert(1, bigdigitsarray.delete_at(0)) 
    end
  return bigdigitsarray.join.to_i
end

代码超时;我不确定为什么无法正确循环。任何帮助将不胜感激!

编辑-我已经弄清了为什么存在无限循环,但是如果有人对解决更大的问题有任何建议,我现在暂时不作讨论!

3 个答案:

答案 0 :(得分:0)

如果您没有自己创建数字数组的任务,可以使用Array#permutation方法根据原始数字生成所有数字组合。

然后,在进行一些清理和排序后,您可以找到电话号码的索引,然后加1以查找下一个最高的电话号码。

def next_number(i)
  puts "Your number is #{i}"
  permutations = i.to_s.split('').permutation.to_a.map(&:join).map(&:to_i).uniq.sort
  index = (permutations.find_index(i) + 1)

  puts "Next highest is #{permutations[index]}"
end

# Usage
next_number(4357)
next_number(81541)

注意事项:

  • 如果您的数字是最高排列的(例如next_number(999)),则不会解决
  • 如果这是代码挑战的一部分,可能不是“最快”的方法

答案 1 :(得分:0)

您正在使用while循环,其中while条件中使用的变量在循环内不会更改。

一种通过蛮力解决问题的方法是在Array#permutation数组上使用Integer#digits

n = 1231
n.digits.permutation.uniq.map { |e| e.join.to_i }.sort.keep_if { |k| k > n }.first
#=> 1312

它使用Array#keep_if来使所有数字(k)大于n

如果没有最大数量,则返回nil


使用Enumerable#partition,您可以看到“里面有什么”:

n.digits.permutation.uniq.map { |e| e.join.to_i }.sort.partition { |k| k > n }
#=> [[1312, 1321, 2113, 2131, 2311, 3112, 3121, 3211], [1123, 1132, 1213, 1231]]

答案 2 :(得分:0)

让我们开始创建一个方法,该方法的参数digits是一个数字数组,并返回一个(“计数”)哈希,其键是数字0-9,其值是digits.count(d)每个键d

def count_digits(digits)
  digits.each_with_object((0..9).to_a.product([0]).to_h) { |d,h| h[d] += 1 }
end

例如,

digits = 35145.digits
  #=> [5, 4, 1, 5, 3] 
digit_counts = count_digits(digits)
  #=> {0=>0, 1=>1, 2=>0, 3=>1, 4=>1, 5=>2, 6=>0, 7=>0, 8=>0, 9=>0}

(请参见Array#productInteger#digits)。现在,我们可以编写一个返回所需结果的方法。

def next_smallest(n)
  digits = n.digits
  digit_counts = count_digits(digits)
  (n-1).downto(0).find { |m| count_digits(m.digits) == digit_counts }
end

require 'time'

def doit(n)
  t = Time.now
  n = next_smallest(n)
  puts "Elapsed time in seconds = #{(Time.now-t).round(7)}"
  n
end

doit  44444
  # Elapsed time in seconds = 0.2008061
  #=> nil 
doit  35154
  # Elapsed time in seconds = 5.18e-05
  #=> 35145 
doit  35154217464215716524742391453862
  # Elapsed time in seconds = 0.0005618
  #=> 35154217464215716524742391453826 
doit  351542174642157165247423914538623999
  # Elapsed time in seconds = 3.4207082
  #=> 351542174642157165247423914538399962 

尽管可能有些学术性,但我们可以做得更好。根据上文的digitsdigit_counts,为

更新digits
n = 35153

我们可以写(因为最后一位大于零):

digits[0] -= 1
digits
  #=> [4, 4, 1, 5, 3] 

类似地,在复制digit_counts的深层副本之后:

h = digit_counts.transform_values(&:itself)
  #=> {0=>0, 1=>1, 2=>0, 3=>1, 4=>1, 5=>2, 6=>0, 7=>0, 8=>0, 9=>0}

我们可以通过编写以下内容来更新此哈希:

d0 = digits.first
  #=> 4 
h[d0] += 1
h[d0+1] -= 1
h #=> {0=>0, 1=>1, 2=>0, 3=>1, 4=>2, 5=>1, 6=>0, 7=>0, 8=>0, 9=>0} 

而不是调用count_digits。 (请参见Hash#transform_values)。现在,让我们对方法进行如下修改。

def next_smallest(n)
  digits = n.digits
  digit_counts = count_digits(digits)
  h = digit_counts.transform_values(&:itself)
  (n-1).downto(10).find do |m|
    d0 = digits.first
    if d0 > 0
      digits[0] -= 1
      h[d0] -= 1
      h[d0-1] += 1
    else
      digits = m.digits
      h = count_digits(digits)
    end
    h == digit_counts
  end
end

doit  44444
  # Elapsed time in seconds = 0.0607323
  #=> nil 
doit  35154
  # Elapsed time in seconds = 0.0001582
  #=> 35145 
doit  35154217464215716524742391453862
  # Elapsed time in seconds = 0.000216
  #=> 35154217464215716524742391453826 
doit  351542174642157165247423914538623999
  # Elapsed time in seconds = 0.5180595
  #=> 351542174642157165247423914538399962 

在最后一位为零的情况下,可以进一步改进(避免调用count_digits)。例如,如果

n = 2130
digits = n.digits
  #=> [0, 3, 1, 2]
h = count_digits(digits)
  #=> {0=>1, 1=>1, 2=>1, 3=>1, 4=>0, 5=>0, 6=>0, 7=>0, 8=>0, 9=>0}

digitsh可以为n = 2129进行如下更新:

n -= 1
  #=> 2129
d1 = digits[1] 
  #=> 3 
digits
  #=> [9, 2, 1, 2] 
h[0] -= 1
h[9] += 1
h[d1] -= 1
h[d1-1] += 1
h #=> {0=>0, 1=>1, 2=>2, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0, 8=>0, 9=>1} 

如果使用n = 21002000,则可以执行类似的操作,但是仅调用count_digits就会很快变得更快