Ferramenta de pesquisa binária ("bissect")


8

Implemente o algoritmo de pesquisa binária conforme usado para identificar a revisão do código fonte que interrompe um programa de software de computador. Sua ferramenta deve usar dois argumentos, especificando a revisão numerada mais antiga e mais recente a ser pesquisada (dois inteiros positivos), e você tem duas opções para fazer comparações:

  1. Execute o comando shell ./test N, onde N é o número da revisão. Se o teste for aprovado ( ou seja, a revisão for boa), ele retornará o código de saída 0.

  2. Chame a função test(N), que retornará truese o teste for aprovado, falsecaso contrário.

A saída padrão deve ser o número da primeira revisão incorreta e tente tornar o código-fonte da sua ferramenta o mais curto possível. Aproveitar!


Apenas alguns esclarecimentos, você quer um script ou apenas uma função?
Nemo157

@ Nemo157: Um script completo. Incluo a test(N)opção de função principalmente para ser justo com as linguagens de programação sem uma maneira padrão de executar comandos do shell, como JavaScript.
PleaseStand

Respostas:


4

Ruby - 92 82 62 60 caracteres

A iterativa é bem mais curta, mas nem de longe tão legal quanto a cauda recursiva.

l,h=$*.map &:to_i
test(m=(l+h)/2)?l=m+1:h=m-1 while l<=h
p l

O método recursivo da cauda antiga para referência

b=proc{|l,h|h<l ?l:(m=(l+h)/2;test(m)?l=m+1:h=m-1;redo)}
puts b[*$*.map(&:to_i)]

Script de teste

Usa um pouco de mágica para injetar a testfunção e executa um arquivo que consiste apenas no código acima.

low = Random.rand(100)
mid = low + Random.rand(1e25)
high = mid + Random.rand(1e50)

File.open('./bisect-test-method.rb','w') do |file|
  file << "def test(value)
             value < #{mid}
           end
          "
end

puts "Using input:"
puts "  low=#{low}"
puts "  high=#{high}"
puts "  first_bad=#{mid}"
puts "Output: #{`ruby -r ./bisect-test-method golf-bisect.rb #{low} #{high}`}"

Resultado:

Using input:
  low=4
  high=75343785543465286986587973836706907796015092187720
  first_bad=5013102893257647460384884
Output: 5013102893257647460384884

5

Python, 64 caracteres

Este é recursivo, então sobrecarregará a pilha para uma entrada realmente grande

01234567890123456789012345678901234567890123456789012345678901234567890
|         |         |         |         |         |         |         |
 B=lambda L,H:H>L+1 and B(*[L,L/2+H/2,H][test(L/2+H/2):][:2])or H

teste de execução

def test(n):
    print "testing ", n
    return n<66

L,H=10,1000


B=lambda L,H:H>L+1 and B(*[L,L/2+H/2,H][test(L/2+H/2):][:2])or H

print B(L,H)

saídas

testing  505
testing  257
testing  133
testing  71
testing  40
testing  55
testing  62
testing  66
testing  64
testing  65
66

Deve imprimir 66, não 65 (retornar H, não L).
Keith Randall

@Keith, ok mudou isso
gnibbler

2

Python - 77 caracteres

Abusando do módulo python bisect. L é o valor baixo, H é o valor alto

class B:__getitem__=lambda s,n:test(n)
import bisect as b
b.bisect(B(),0,L,H)

aqui está um teste

def test(n):
    print "testing ", n
    return n>66
L,H=10,1000

class B:__getitem__=lambda s,n:test(n)
import bisect as b
b.bisect(B(),0,L,H)

saídas

testing  505
testing  257
testing  133
testing  71
testing  40
testing  56
testing  64
testing  68
testing  66
testing  67

Explicação:

Aqui está como o bisseto é definido. Basicamente, ele espera uma lista e decide se deve dividir para cima ou para baixo com base no valor que encontra olhando a[mid]. Isto chama __getitem__em aque em vez de ser uma lista, é uma classe que eu me definido.

def bisect_right(a, x, lo=0, hi=None):
    """Return the index where to insert item x in list a, assuming a is sorted.

    The return value i is such that all e in a[:i] have e <= x, and all e in
    a[i:] have e > x.  So if x already appears in the list, a.insert(x) will
    insert just after the rightmost x already there.

    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        if x < a[mid]: hi = mid
        else: lo = mid+1
    return lo

bisect=bisect_right

2

Python - 70 caracteres

def B(L,H):
 while L+1<H:M=L+H;L,H=[L,M/2,H][test(M/2):][:2]
 return L

teste de execução

def test(n):
    print "testing ", n
    return n<66
L,H=10,1000

def B(L,H):
 while L+1<H:M=L+H;L,H=[L,M/2,H][test(M/2):][:2]
 return L

print B(L,H)

saídas

testing  505
testing  257
testing  133
testing  71
testing  40
testing  55
testing  63
testing  67
testing  65
testing  66
65
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.