Densidade de dígitos numéricos quadrados

17

A densidade de dígitos numéricos quadrados (SNDD) de um número - inventado por mim mesmo - é a razão entre a contagem de números quadrados encontrados em dígitos consecutivos e o comprimento do número. Por exemplo, 169 é um número de 3 dígitos contendo 4 números quadrados - 1, 9, 16, 169 - e, portanto, possui uma densidade de dígitos numéricos quadrados de 4/3 ou 1,33. O número de 4 dígitos 1444 possui 6 quadrados - 1, 4, 4, 4, 144, 1444 - e, portanto, uma proporção de 6/4 ou 1,5. Observe no exemplo anterior que os quadrados podem ser repetidos. Além disso, 441 não é permitido, porque não pode ser encontrado consecutivamente dentro do número 1444.

Sua tarefa é escrever um programa que procure um determinado intervalo A - B (inclusive) pelo número com a maior densidade de dígitos do número quadrado. Seu programa deve obedecer às seguintes especificações:

  • Considere a entrada A, B no intervalo de 1 a 1.000.000.000 (1 bilhão). Exemplo:sndd 50 1000
  • Retorne como resultado o número com o maior SNDD. Em caso de empate, retorne o menor número.
  • 0 não conta como um quadrado de qualquer forma, 0, 00, 000, etc. Nem os quadrados que começam com 0, como 049 ou 0049.
  • Observe que o número inteiro não precisa ser um número quadrado.

Exemplos:

sndd 14000 15000
Output: 14441

sndd 300 500
Output: 441

Bônus: Qual é o número com o maior SNDD entre 1 e 1.000.000.000? Você pode provar se essa é a maior possível ou se pode haver uma maior em uma faixa maior?

Pontuações atuais:

  1. Ruby: 142
  2. Windows PowerShell: 153
  3. Scala: 222
  4. Python: 245

Agora que uma resposta foi selecionada, eis a minha implementação de referência (não destruída) em JavaScript: http://jsfiddle.net/ywc25/2/

mellamokb
fonte

Respostas:

3

Ruby 1.9, 142 caracteres

$><<($*[0]..$*[1]).map{|a|n=0.0;(1..s=a.size).map{|i|n+=a.chars.each_cons(i).count{|x|x[0]>?0&&(r=x.join.to_i**0.5)==r.to_i}};[-n/s,a]}.min[1]
  • (139 -> 143): Saída fixa em caso de empate.
Ventero
fonte
@ Ventero: falha nos dois casos de teste. Eu acho que você está esquecendo de deixar de fora os quadrados começando com 0 *
mellamokb
@mellamokb: não deixa-los aqui: $ ruby1.9 sndd.rb 14000 15000 => 14441. x[0]>?0verifica quadrados começando com 0.
Ventero
@ellamokb: Passa nos casos de teste aqui.
Nabb
@ Ventero: Hmm .. algo deve estar errado com o meu ambiente de teste de rubi. Eu não estou familiarizado com Ruby. Eu tenho 1,87, eu acho, e eu copiei / colei o código acima no sndd.rb, em seguida, corro com o ruby sndd.rb 14000 15000Windows, recebo 14000.
mellamokb
@mellamokb: No Ruby 1.8, ?0é um Fixnum, enquanto no Ruby 1.8 é uma string, então a comparação que eu mencionei tem um significado diferente dependendo da versão do Ruby (na verdade, ele deve lançar uma exceção no 1.8). Por isso mencionei explicitamente a versão 1.9 no título.
Ventero
8

Respondendo ao bônus: a melhor pontuação para números <1e9 é 5/3 = 1.666 ..., gerada por 144411449 (e talvez outros?).

Mas você pode fazer melhor com números maiores. Geralmente, se n tem uma pontuação de x, você pode concatenar duas cópias de n e obter a mesma pontuação x. Se você tiver sorte en tiver o mesmo primeiro e último dígito, poderá soltar um desses dígitos na concatenação e melhorar sua pontuação ligeiramente (um a menos que o dobro do número de quadrados e um a menos que o dobro do número de dígitos) .

n = 11449441 tem uma pontuação de 1,625 e tem o mesmo primeiro e último dígito. Usando esse fato, obtemos a seguinte sequência de pontuações:

1.625 for 11449441
1.666 for 114494411449441
1.682 for 1144944114494411449441
1.690 for 11449441144944114494411449441
1.694 for 114494411449441144944114494411449441

que fornece uma sequência infinita de números que são estritamente (embora decrescentemente) melhores que os números anteriores, e todos, exceto os 2 primeiros, melhores que a melhor pontuação para números <1e9.

Porém, essa sequência pode não ser a melhor em geral. Ele converge para uma pontuação finita (12/7 = 1.714) e pode haver outros números com pontuações melhores que o limite.

Editar : uma sequência melhor, converge para 1,75

1.600 14441
1.667 144414441
1.692 1444144414441
1.706 14441444144414441
1.714 144414441444144414441
Keith Randall
fonte
Interessante! Você pode ter acabado de provar que essa sequência é realmente infinita.
ESultanik
@ESultanik: Na verdade não, porque aqui não há exigência de que o número geral seja um quadrado perfeito.
mellamokb
@ESutanik: Eu não acho que a sequência esteja relacionada, pois eles exigem que o número inteiro seja um quadrado - na minha sequência os únicos quadrados são pequenas subsequências (<= 5 dígitos), a menos que, por acidente, haja uma maior.
Keith Randall
Você também pode gerar uma sequência infinita em que o link gera um quadrado extra, ou seja, algo que termina em 44 e começa com 1 faria um 441 com cada combinação. Um exemplo trivial, poderia ser a sequência 144, 144144, 144144144, etc
mellamokb
@mellamokb Uau, eu perdi totalmente que o número não precisava ser um quadrado perfeito. Você está certo.
ESultanik
3

Windows PowerShell, 153 154 155 164 174

$a,$b=$args
@($a..$b|sort{-(0..($l=($s="$_").length)|%{($c=$_)..$l|%{-join$s[$c..$_]}}|?{$_[0]-48-and($x=[math]::sqrt($_))-eq[int]$x}).Count/$l},{$_})[0]

Graças a Ventero por uma redução de um byte, fui burra demais para me encontrar.

Versão de 154 bytes explicada:

$a,$b=$args   # get the two numbers. We expect only two arguments, so that
              # assignment will neither assign $null nor an array to $b.

@(   # @() here since we might iterate over a single number as well
    $a..$b |  # iterate over the range
        sort {   # sort
            (   # figure out all substrings of the number
                0..($l=($s="$_").length) | %{  # iterate to the length of the
                                               # string – this will run off
                                               # end, but that doesn't matter

                    ($c=$_)..$l | %{       # iterate from the current position
                                           # to the end

                        -join$s[$c..$_]    # grab a range of characters and
                                           # make them into a string again
                    }
                } | ?{                     # filter the list
                    $_[0]-48 -and          # must not begin with 0
                    ($x=[math]::sqrt($_))-eq[int]$x  # and the square root
                                                     # must be an integer
                }

            ).Count `  # we're only interested in the count of square numbers
            / $l       # divided by the length of the number
        },
        {-$_}  # tie-breaker
)[-1]  # select the last element which is the smallest number with the
       # largest SNDD
Joey
fonte
2

Python, 245 256

import sys
def t(n,l):return sum(map(lambda x:int(x**0.5+0.5)**2==x,[int(n[i:j+1])for i in range(l)for j in range(i,l)if n[i]!='0']))/float(l)
print max(map(lambda x:(x,t(str(x),len(str(x)))),range(*map(int,sys.argv[1:]))),key=lambda y:y[1])[0]
  • 256 → 245: limpo o código de análise de argumentos graças a uma dica de Keith Randall .

Isso poderia ser muito menor se o intervalo fosse lido de stdin em oposição aos argumentos da linha de comando.

Editar:

Com relação ao bônus, minhas experiências sugerem o seguinte:

Conjectura 1 . Para cada n ∈ ℕ , o número em with n com o maior SNDD deve conter apenas os dígitos 1, 4 e 9.

Conjectura 2.n ∈ ∀ i ∈ ℕ n : SNDD ( n ) ≥ SNDD ( i ).

Esboço de prova . O conjunto de quadrados com os dígitos 1, 4 e 9 provavelmente é finito . ∎

ESultanik
fonte
Tenterange(*map(int,sys.argv[1:]))
Keith Randall
11
A conjectura 2 é falsa se a sequência convergente de 1,75 na minha resposta produz as melhores pontuações (uma grande se, é certo), pois os elementos subsequentes da sequência são marginalmente melhores para sempre.
Keith Randall
A conjectura 2 é falsa pela resposta de @ Arnt, porque o valor do SNDD pode ser arbitrariamente grande.
precisa saber é o seguinte
2

Scala, 222

object O extends App{def q(i: Int)={val x=math.sqrt(i).toInt;x*x==i}
println((args(0).toInt to args(1).toInt).maxBy(n=>{val s=n+""
s.tails.flatMap(_.inits).filter(x=>x.size>0&&x(0)!='0'&&q(x.toInt)).size.toFloat/s.size}))}

(Scala 2.9 necessário.)

Rex Kerr
fonte
1

Considerando a questão do bônus: Fora do intervalo, o SNDD mais alto possível é infinito.

Pelo menos, se eu li a pergunta corretamente, um quadrado como 100 (10 * 10) conta.

Se você considerar o número 275625, a pontuação será 5/6, pois 25, 625, 5625, 75625 e 275625 são todos quadrados.

Se adicionar 2 zeros, obtém-se: 27562500, que tem uma pontuação de 10/8. O limite desta sequência é 5/2 = 2,5

Na mesma linha, você pode encontrar quadrados que terminam em qualquer número de quadrados menores desejado. Eu posso provar isso, mas você provavelmente entendeu a idéia.

É certo que essa não é uma solução muito boa, mas prova que não há limite superior para o SNDD.

Arnt Veenstra
fonte
"'Na mesma linha, você pode encontrar quadrados que terminam com qualquer número de quadrados menores desejado. Eu posso provar isso, mas você provavelmente entendeu a idéia." Eu gostaria de ver essa prova desenvolvida. Eu posso ver a maior sequência que termina em 25, onde todo número que termina em 25 é um quadrado é 275625. Não há dígitos de 1 a 9 que você pode colocar no início para encontrar outro quadrado. Você está dizendo que isso pode ser arbitrariamente grande e, em caso afirmativo, como e por quê?
precisa saber é o seguinte
Sim, a sequência pode ser arbitrariamente grande. A prova é a seguinte: se a * a = b é o seu número inicial, (a + 10 ^ c) * (a + 10 ^ c) também termina em b se c for suficientemente grande. Na prática, pode haver números menores que terminam em b se você pegar o quadrado. Por exemplo, 18275625 é um quadrado (4275 * 4275).
Arnt Veenstra
Código para encontrar quadrados: jsfiddle.net/zVSuZ/2
mellamokb
@Arnt: Aqui está uma sequência (trivial), 5 ^ 2 (1/2), 55 ^ 2 (2/4), 5055 ^ 2 (3/8), 50005055 ^ 2 (4/16), etc. onde cada adição é 5 * 10 ^ n, onde n é duas vezes a entrada anterior. Cada entrada fica menor em pontuação, mas o limite ao aplicar a regra de adicionar dois 00 aumenta marginalmente, então os limites são (1/2), (2/2), (3/2), (4/2), etc. .
mellamokb
Sim, essa é a ideia que prova que qualquer valor para o SNDD pode ser alcançado.
Arnt Veenstra
1

Clojure - 185 caracteres

Provavelmente poderia ser otimizado ainda mais, mas aqui vai:

(fn[A,B]((first(sort(for[r[range]n(r A(inc B))s[(str n)]l[(count s)]][(/(count(filter #(=(int%)(max 1%))(for[b(r(inc l))a(r b)](Math/sqrt(Integer/parseInt(subs s a b))))))(- l))n])))1))

Usado como uma função com dois parâmetros:

(crazy-function-as-above 14000 15000)
=> 14441
Mikera
fonte
1

Jelly , 21 bytes, desafio pós-datas no idioma

DµẆ1ị$ÐfḌƲS÷L
rµÇÐṀḢ

Experimente online!

Explicação

Função auxiliar (calcula a densidade de dígitos de sua entrada):

DµẆ1ị$ÐfḌƲS÷L
Dµ              Default argument: the input's decimal representation
  Ẇ             All substrings of {the decimal representation}
      Ðf        Keep only those where
   1ị$          the first digit is truthy (i.e. not 0)
        Ḍ       Convert from decimal back to an integer
         Ʋ     Check each of those integers to see if it's square
           S    Sum (i.e. add 1 for each square, 0 for each nonsquare)
            ÷L  Divide by the length of {the decimal representation}

Programa principal:

rµÇÐṀḢ
rµ              Range from the first input to the second input
  ÇÐṀ           Find values that maximize the helper function
     Ḣ          Choose the first (i.e. smallest)

O programa é discutivelmente mais interessante sem o - dessa forma, ele retorna todos os números de densidade máxima em vez de apenas um - mas eu o adicionei para atender à especificação.


fonte