Tìm tổng khoảng cách gần nhất


10

Đối với tác vụ này, mã của bạn sẽ lấy hai mảng số nguyên X và Y được sắp xếp làm đầu vào. Cần tính tổng khoảng cách tuyệt đối giữa mỗi số nguyên trong X và số gần nhất của nó trong Y.

Ví dụ:

X = (1 5,9)
Y = (3,4,7)

Khoảng cách là 2 + 1 + 2.

X = (1,2,3)
Y = (0,8)

Khoảng cách là 1 + 2 + 3.

Mã của bạn có thể nhận đầu vào theo bất kỳ cách nào thuận tiện.

Hạn chế chính là mã của bạn phải chạy trong thời gian tuyến tính tính tổng độ dài của hai mảng. . (Bạn có thể giả sử rằng việc thêm hai số nguyên cần có thời gian không đổi.)


Chúng ta có thể sử dụng danh sách hoặc luồng thay vì mảng không?
Ad Hoc Garf Hunter

@CatWizard Có bạn có thể!
Anush

1
Làm thế nào có 1 + 2 + 3nguồn gốc từ X = (1,2,3)Y = (0,8)?
khách271314

1
@ guest271314 số gần hai từng 1, 23trong Y0. Như vậy sự khác biệt là 1-0, 2-0, 3-0.
dylnan

1
@FreezePhoenix vì cả hai danh sách được sắp xếp, bạn có thể thực hiện điều đó trong O (n + m), vì bạn lặp lại danh sách , truy cập từng phần tử một lần và miễn là bạn theo dõi phần tử gần nhất với , bạn có thể kiểm tra lại và vì một trong số đó gần nhất vớiY j X i Y j Y j + 1 X i + 1XYjXiYjYj+1Xi+1
Giuseppe

Câu trả lời:


6

Haskell , 70 64 byte

a%b=abs$a-b
x@(a:b)#y@(c:d)|e:_<-d,a%c>a%e=x#d|1>0=a%c+b#y
_#_=0

Hãy thử trực tuyến!

Giải trình

Đầu tiên chúng tôi xác định (%)là sự khác biệt tuyệt đối giữa hai số. Sau đó, chúng tôi xác định (#)là chức năng thú vị. Trong dòng đầu tiên, chúng tôi khớp khi cả hai danh sách không trống:

x@(a:b)#(c:d:e)

Mở trường hợp đầu tiên của chúng tôi từ đây chúng ta ràng buộc dđể e:_e:_<-d. Điều này đảm bảo dkhông trống và đặt thành phần đầu tiên của nó thành e.

Sau đó, nếu phần tử thứ hai của ( ) là gần hơn là người đầu tiên ( ) đến phần tử đầu tiên của X ( ), chúng tôi trở lại loại bỏ phần tử đầu tiên của Y và gọi lại với cùng X .YecXax#dYX

Nếu chúng ta khớp mẫu nhưng không vượt qua điều kiện chúng ta sẽ làm:

a%c+b#y

Trong đó, loại bỏ mục đầu tiên của và thêm sự khác biệt tuyệt đối của nó từ phần tử đầu tiên của X vào kết quả còn lại.XX

Cuối cùng, nếu chúng ta không khớp với mẫu chúng ta trả về . Không khớp với mẫu có nghĩa là X phải trống vì Y không thể trống.0XY

Thuật toán này có ký hiệu thứ tự .Ôi(|X|+|Y|)

Haskell , 34 byte

Đây là cách tôi sẽ làm trong thời gian :Ôi(|X|×|Y|)

x#y=sum[minimum$abs.(z-)<$>y|z<-x]

Hãy thử trực tuyến!


Tôi đã làm rõ trong câu hỏi rằng chúng ta có thể giả sử rằng việc thêm hai số nguyên cần thời gian không đổi.
Anush

2

Python 2 , 124 120 byte

X,Y=input()
i=j=s=0
while i<len(X):
 v=abs(Y[j]-X[i])
 if j+1<len(Y)and v>=abs(Y[j+1]-X[i]):j+=1
 else:s+=v;i+=1
print s

Hãy thử trực tuyến!

Đã lưu 4 byte bằng cách di chuyển đến chương trình so với chức năng.

Đáp ứng các ràng buộc về độ phức tạp thời gian là có thể bởi vì cả hai danh sách được sắp xếp. Lưu ý rằng mỗi lần xung quanh vòng lặp, hoặc ilà tăng hoặc jtăng. Do đó, vòng lặp được thực hiện tại hầu hết các len(X)+len(Y)lần.


Tôi đã làm rõ trong câu hỏi rằng chúng ta có thể giả sử việc thêm hai số nguyên cần thời gian không đổi.
Anush

1

C (gcc), 82 byte

n;f(x,y,a,b)int*x,*y;{for(n=0;a;)--b&&*x*2-*y>y[1]?++y:(++b,--a,n+=abs(*x++-*y));}

Điều này nhận đầu vào là hai mảng số nguyên và độ dài của chúng (vì C không có cách nào để lấy chiều dài của chúng theo cách khác). Điều này có thể được hiển thị để chạy trong O(a+b)bởi vì ahoặc blà giảm dần trên mỗi lần lặp của vòng lặp, kết thúc khi ađạt 0(và bkhông thể giảm xuống bên dưới 0).

Hãy thử trực tuyến!

n;                     // define sum as an integer
f(x,y,a,b)             // function taking two arrays and two lengths
int*x,*y;              // use k&r style definitions to shorten function declaration
{
 for(n=0;              // initialize sum to 0
 a;)                   // keep looping until x (the first array) runs out
                       // we'll decrement a/b every time we increment x/y respectively
 --b&&                 // if y has ≥1 elements left (b>1, but decrements in-place)...
 *x*2-*y>y[1]?         // ... and x - y > [next y] - x, but rearranged for brevity...
 ++y:                  // increment y (we already decremented b earlier);
 (++b,                 // otherwise, undo the in-place decrement of b from before...
 --a,n+=abs(*x++-*y))  // decrement a instead, add |x-y| to n, and then increment x
;}

Một số lưu ý:

  • Thay vì lập chỉ mục vào mảng, incrementing các con trỏ và dereferencing trực tiếp tiết kiệm đủ byte cho nó có giá trị nó ( *xvs x[a]y[1]vs y[b+1]).

  • Điều --b&&kiện kiểm tra b>1theo cách vòng - nếu b1, nó sẽ ước tính bằng không. Vì điều này sửa đổi b, chúng tôi không cần phải thay đổi nó trong nhánh đầu tiên của ternary (tiến bộ y), nhưng chúng tôi cần phải thay đổi nó trở lại trong lần thứ hai (tiến bộ x).

  • Không có returntuyên bố là cần thiết, bởi vì ma thuật đen. (Tôi nghĩ đó là vì câu lệnh cuối cùng được đánh giá sẽ luôn là n+=...biểu thức, sử dụng cùng một thanh ghi như câu lệnh được sử dụng cho các giá trị trả về.)


0

Ruby, 88 byte

->(p,q){a=q.each_cons(2).map{|a|a.sum/a.size}
x=a[0]
p.sum{|n|x=a.pop if n>x
(n-x).abs}}

Hãy thử trực tuyến!

Ngoài ra, để giải trí, một chức năng ẩn danh ngắn hơn không đáp ứng được các hạn chế phức tạp:

->(a,b){a.map{|x|x-b.min_by{|y|(x-y).abs}}.sum}

Bạn có thể giải thích một cách đơn giản về cách thức hoạt động của mã này? Tôi không thể biết nếu nó chạy trong thời gian tuyến tính.
Anush

2
Điều này không thành công trong trường hợp thử nghiệm đầu tiên trong câu hỏi, cũng như các đầu vào như [5, 6], [0, 1, 5].
Doorknob

0

JavaScript (Node.js) , 80 byte

x=>g=(y,i=0,j=0,v=x[i],d=v-y[j],t=d>y[j+1]-v)=>1/v?g(y,i+!t,j+t)+!t*(d>0?d:-d):0
  • Nó chạy trong O (| X | + | Y |): Mọi đệ quy chạy trong O (1) và nó đệ quy | X | + | Y | lần
    • x, yđược truyền bằng tham chiếu, không sao chép nội dung
  • 1/vlà giả nếu x[i]nằm ngoài phạm vi, sự thật khác
  • t-> d>y[j+1]-v-> v+v>y[j]+y[j+1]là sai miễn là đáp ứng các điều kiện sau đây. Và có nghĩa y[j]là số gần nhất vtrongy
    • vít hơn (y[j]+y[j+1])/2, hoặc
    • y[j+1]nằm ngoài phạm vi, sẽ chuyển đổi thành NaNvà so sánh với NaNnăng suấtfalse
      • đó là lý do tại sao chúng ta không thể lật >ký hiệu để tiết kiệm thêm 1 byte
  • tluôn luôn là một giá trị boolean và *chuyển đổi nó thành 0/ 1trước khi tính toán

Hãy thử trực tuyến!


0

Toán học, 40 byte

x = {1, 5, 9};
y = {3, 4, 7};

Norm[Flatten[Nearest[y] /@ x] - x]

Nếu bạn phải tạo một chương trình đầy đủ, với đầu vào:

f[x_,y_]:= Norm[Flatten[Nearest[y] /@ x] - x]

Đây là thời điểm lên tới 1.000.000 điểm (được lấy mẫu sau mỗi 10.000) cho y:

nhập mô tả hình ảnh ở đây

Gần tuyến tính.


1
Câu trả lời này là một đoạn mã vì đầu vào của bạn được lấy làm biến trước đó. Bạn nên định dạng lại nó thành một chương trình con hoặc một chương trình đầy đủ.
Ad Hoc Garf Hunter

Tôi cũng hơi nghi ngờ rằng điều này hoạt động trong thời gian tuyến tính, bạn có bất cứ lý do nào giải thích tại sao nó nên không? Mathematica có xu hướng khá mờ đục trong sự phức tạp của các nội trang của nó.
Ad Hoc Garf Hunter
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.