Thuật toán để khớp số với số lần di chuyển tối thiểu


11

Đây là một loại câu hỏi khoảng cách chỉnh sửa, và rất dễ dàng. Tôi khá là chết não về chủ đề này và không thể tìm ra nó cho đến nay.


Cho một loạt các số, ví dụ

[3, 1, 1, 1]

Làm thế nào một cách hiệu quả nhất có thể biến tất cả các số thành cùng một số, với số lần "di chuyển" tối thiểu? Bằng cách "di chuyển" có nghĩa là thêm hoặc xóa một từ một số.

Trong ví dụ trên, các động thái hiệu quả nhất sẽ là:

[1, 1, 1, 1]

Điều này sẽ cần 2 lần di chuyển, giảm số thứ nhất hai lần.

Tôi không thể tìm ra cách tốt nhất để tìm ra điều này, với các mảng lớn hơn hàng trăm số.

Ban đầu tôi đã thử tính số trung bình làm tròn (tổng của tất cả chia cho chiều dài), sau đó giảm chúng xuống mức trung bình được tính, nhưng ví dụ trên đã phá vỡ điều này, yêu cầu 4 di chuyển thay vì 2.

Tôi cho rằng tôi có thể hình:

  1. Trung bình,
  2. Chế độ,
  3. Trung vị

và lấy khoảng cách chỉnh sửa của từng cái, chọn khoảng cách tối thiểu. Tuy nhiên, tôi không chắc chắn rằng điều này sẽ đúng trong mọi trường hợp. Làm sao tôi biết được?


Nếu tên miền bị giới hạn, bạn có thể thử tất cả các khả năng từ tối thiểu đến tối đa. Nếu không, bạn có thể thử sử dụng chế độ hoặc trung vị.
Bartosz Przybylski

Cảm ơn @Bartek. Có vẻ như thử tất cả các khả năng sẽ rất kém hiệu quả nếu xử lý hàng trăm hoặc hàng ngàn số. Tôi sẽ kiểm tra chế độ / trung vị. Nhưng những điều này có chắc chắn để tạo ra kết quả trong mọi trường hợp? Đó là câu hỏi chính của tôi. Tôi đang tìm kiếm một thuật toán nhất định, hiệu quả.
dthree

Số có phải nằm trong tập hợp số hay có thể là số nguyên không?
TCSGrad

@TCSGrad Nó có thể là bất kỳ số nguyên nào, nhưng rõ ràng bạn sẽ muốn chọn một số nằm giữa số tối thiểu và tối đa. Trong trường hợp này, 1, 2 hoặc 3.
dthree

Câu trả lời:


10

Câu trả lời là lấy trung vị. Một trong những tính chất của trung vị là nó thu nhỏ khoảng cách L1 đến từng phần tử. (Để hiểu ý nghĩa của bài viết Wikipedia, hãy lấy phân phối xác suất làm phân phối thống nhất trên chuỗi số ban đầu của bạn).

Đây là thuật toán giải quyết vấn đề (ban đầu được viết bởi dc2 ):

function median(arr) {
  arr.sort(function(a, b) { return a - b; });
  var half = floor(arr.length/2);
  if ( arr.length % 2 ) {
    return arr[half];
  } else {
    return (arr[half-1] + arr[half]) / 2.0;
  }
}

function minl1(arr) {
  var moves = 0;
  var mdn = median(arr);
  for ( var i = 0; i < arr.length; ++i ) {
    moves += Math.abs(mdn - arr[i]);
  }
  return moves;
}

minl1([3, 1, 1, 1]); // -> 2

Vâng, điều đó đã làm nó. Hài hước làm thế nào mà hoạt động. Không có vẻ như trung bình sẽ làm điều đó, nhưng hey. Cảm ơn rất nhiều.
dthree

1
Xem câu trả lời của tôi cho một bằng chứng.
Yuval Filmus

@ dc2: Bạn không thể "đảm bảo" bằng cách "dùng thử".
Raphael

1
Chỉ cần lưu ý: bạn có thể tính thời gian trung bình O (n)
Bartosz Przybylski

1
@Raphael Có thể bao gồm mã của OP trong một số câu trả lời khác, không có tham chiếu đến OP?
thefourtheye

10

Như TCSGrad đã đề cập, đưa ra một danh sách các số nguyên , bạn đang tìm số nguyên thu nhỏ Hướng dẫn tính toán : Khi đi từ đến , đại lượng đi từ đến . Hơn nữa, nó chỉ chuyển đổi giá trị tại các điểmx1,,xnm

δ(m)=i=1n|mxi|.
δ(m+1)δ(m)
δ(m+1)δ(m)=i=1n{+1mxi1m<xi=#{i:mxi}#{i:m<xi}.
m+δ(m+1)δ(m)nnx1,,xn. Không khó để kiểm tra xem giá trị tối ưu của là điểm tối thiểu tại đó . Điểm tối thiểu này là một trong , vì vậy khoảng cách chỉnh sửa là .mδ(m+1)δ(m)0ximin(δ(x1),,δ(xn))

Giả sử thêm rằng tất cả là khác biệt và là số lẻ. Gọi là trung tuyến của . Khi đó while , và do đó là tối ưu duy nhất. Nếu chẵn thì một phép tính tương tự cho thấy chúng ta có thể chọn bất kỳ điểm nào trong khoảng thời gian kết nối các trung vị. Lý luận tương tự nhưng phức tạp hơn cho thấy rằng bất kỳ trung vị nào là tối ưu ngay cả khi không khác biệt. Vì vậy, thực sự không cần tính toán trên tất cả .xinmxiδ(m+1)δ(m)=1δ(m)δ(m1)=1mnxiδxi


Bạn có thể đã bỏ lỡ nó, nhưng câu trả lời này (gần như) chứng minh rằng trung vị là lựa chọn tối ưu.
Yuval Filmus

1
câu trả lời của bạn là tuyệt vời và tôi đã nâng cao nó. Thật không may cho tôi, một chút quá xuất sắc vì tôi không rành về ký hiệu khoa học, khiến phần lớn nó bị cắt xén. Đó là vấn đề của tôi, không phải của bạn.
dthree

5

Vấn đề có thể được coi là một vấn đề LP:

Cho một tập hợp số , giải LP sau:n[a1,a2...an]

min|aix|

(Đã xóa các ràng buộc trên , điều không cần thiết như Raphael đã chỉ ra)x

Khi LP được giải quyết, bạn sẽ nhận được giá trị tương ứng với giải pháp. Nếu là một số nguyên, bạn đã hoàn tất - khác, làm tròn nó đến số nguyên gần nhất.xx

EDIT : Như đã chỉ ra trong các ý kiến, hàm mục tiêu nên được tổng hợp trên sự khác biệt tuyệt đối. Để chuyển đổi nó trở lại thành LP tiêu chuẩn, chúng ta có thể viết lại LP dưới dạng:

minai

chủ đề:

aiaix i
aiaix i
ai,x0 i

Ở giải pháp tối ưu, và chúng ta có thể nhận giá trị của từ giải pháp.ai=|aix| ix


Vì vậy, nếu tôi hiểu điều này một cách chính xác, trong ví dụ của tôi, x sẽ là 1 - 3, và vì vậy tôi sẽ tìm khoảng cách chỉnh sửa là 1, 2 và 3, và sau đó thực hiện một phút trên đó?
dthree

@ dc2: Điều này sẽ giảm thiểu tổng khoảng cách giữa mỗi số và , trong đó là số hội tụ. Các ràng buộc đảm bảo LP kết thúc nhanh chóng và không tìm kiếm trên tất cả các số nguyên! xx
TCSGrad

Tại sao các ràng buộc cần thiết?
Raphael
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.