Tìm kiếm nhị phân (công cụ bisect trực tiếp)


8

Thực hiện thuật toán tìm kiếm nhị phân như được sử dụng để xác định sửa đổi mã nguồn phá vỡ chương trình phần mềm máy tính. Công cụ của bạn sẽ có hai đối số chỉ định sửa đổi được đánh số sớm nhất và mới nhất để tìm kiếm (cả hai số nguyên dương) và bạn có hai tùy chọn để so sánh:

  1. Thực hiện lệnh shell ./test N, trong đó N là số sửa đổi. Nếu kiểm tra vượt qua ( tức là sửa đổi là tốt), nó sẽ trả về mã thoát 0.

  2. Gọi hàm test(N), sẽ trả về truenếu kiểm tra vượt qua, falsenếu không.

Đầu ra tiêu chuẩn phải là số lần sửa đổi xấu đầu tiên và cố gắng làm cho mã nguồn của công cụ của bạn càng ngắn càng tốt. Thưởng thức!


Chỉ cần làm rõ một chút, bạn muốn có một kịch bản hay chỉ là một chức năng?
Nemo157

@ Nemo157: Một kịch bản hoàn chỉnh. Tôi bao gồm test(N)tùy chọn chức năng chủ yếu cho sự công bằng với các ngôn ngữ lập trình đó mà không có cách tiêu chuẩn để thực thi các lệnh shell, chẳng hạn như JavaScript.
Xin hãy khởi động

Câu trả lời:


4

Hồng ngọc - 92 82 62 60 ký tự

Lặp lại là cách ngắn hơn, nhưng không nơi nào mát mẻ như đệ quy đuôi.

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

Phương pháp đệ quy đuôi cũ để tham khảo

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)]

Kiểm tra tập lệnh

Sử dụng một phép thuật nhỏ để tiêm testhàm và chạy một tệp hoàn toàn là đoạn mã trên.

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}`}"

Đầu ra:

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

5

Python, 64 ký tự

Cái này là đệ quy, vì vậy sẽ tràn vào ngăn xếp cho đầu vào thực sự lớn

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

chạy thử nghiệm

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)

đầu ra

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

Nên in 66, không phải 65 (trả về H, không phải L).
Keith Randall

@Keith, ok đã thay đổi điều đó
gnibbler

2

Python - 77 ký tự

Lạm dụng mô-đun bisect python. L là giá trị thấp, H là giá trị cao

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

đây là một cuộc chạy thử

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)

đầu ra

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

Giải trình:

Đây là cách chia đôi được định nghĩa. Về cơ bản, nó mong đợi một danh sách và quyết định nên chia đôi lên hay xuống dựa trên giá trị mà nó tìm thấy bằng cách xem xét a[mid]. Đây gọi __getitem__trên a, mà thay vì một danh sách, là một lớp mà tôi đã xác định bản thân mình.

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 ký tự

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

chạy thử nghiệm

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)

đầu ra

testing  505
testing  257
testing  133
testing  71
testing  40
testing  55
testing  63
testing  67
testing  65
testing  66
65
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.