2013-11-03 26 views
6

Tôi muốn tìm giá trị thấp nhất trong một số phạm vi.
Tôi có phải lặp lại mảng mỗi lần hoặc có phương pháp động nào không?Giá trị thấp nhất trong phạm vi

phép nói rằng tôi có mảng đầu vào:

index: 0 1 2 3 4 5 6 7 
value: 1 4 6 1 6 7 2 3 

và sau đó tôi phải chọn nhỏ nhất trong phạm vi < a, b> (bao gồm). Ví dụ:

min(0,7) = 1 
min(0,2) = 1 
min(4,6) = 2 
min(1,2) = 4 

Tôi quan tâm đến giải pháp nhanh nhất, tốt nhất nên lấy kết quả trong thời gian không đổi.

Mảng sẽ không bị thay đổi trong thời gian chờ đợi.

+0

Dường như bạn chỉ cần cho vòng lặp – LeeNeverGup

+0

Và đó là tuyến tính ... Không phải là nó có thể đi nhanh hơn? –

+0

Bạn có thể tính trước kết quả một lần cho mọi phạm vi có thể trong thời gian 'O (N^2)'. Sau đó, tra cứu sẽ là thời gian không đổi. Tùy thuộc vào mức độ thường xuyên bạn cần tìm kiếm trên cùng một dữ liệu, bạn có thể phân bổ chi phí ban đầu. –

Trả lời

7

Nếu bạn định thực hiện nhiều truy vấn trên cùng một tập hợp các số thì bạn sẽ muốn tạo một Cartesian Tree.

Cây Descartes có thể được sử dụng như một phần của cấu trúc dữ liệu hiệu quả cho các truy vấn tối thiểu, phạm vi tìm kiếm yêu cầu giá trị tối thiểu trong chuỗi tiếp giáp của chuỗi gốc.

Như bài viết cho biết, các truy vấn có thể được thực hiện trong thời gian không đổi.

+0

Cấu trúc đẹp, nhưng tôi không chắc chắn cách truy vấn có thể được thực hiện trong thời gian * liên tục *. Tôi sẽ không ngạc nhiên với một O (D) trong đó D là độ sâu của cây ... nhưng hằng số dường như cắt nó mỏng. Trong bài viết gốc, nếu tôi yêu cầu mức tối thiểu trong phạm vi từ 9 đến 18 (là 1), có vẻ mất nhiều thời gian hơn để xác định rằng 10 là tối thiểu trong '[12,10,20,15]' . –

+0

@MatthieuM .: Rất khó. Việc tra cứu bao gồm việc tìm kiếm tổ tiên chung thấp nhất của các nút ranh giới cho truy vấn trong cây. Việc thực hiện đơn giản đó là O (D) như bạn mong đợi, nhưng có những thủ thuật để tìm LCA trong O (1), xem http://en.wikipedia.org/wiki/Lowest_common_ancestor –

-2

Đây là một nhiệm vụ tiêu chuẩn. Bạn có thể sử dụng chức năng thư viện std. Nó phải là nhanh nhất có thể. Ví dụ từ here:

#include <iostream>  // std::cout 
#include <algorithm> // std::min_element, std::max_element 

int main() { 
    int myints[] = {3,7,2,5,6,4,9}; 

    std::cout << "The smallest element is " << *std::min_element(myints,myints+7) << '\n'; 

    return 0; 
} 

T.B. Bạn không thể nhận được kết quả trong thời gian không đổi, vì nếu bạn cần tối thiểu giữa các phần tử N, bạn cần kiểm tra từng phần tử. Độ phức tạp của tác vụ tối thiểu là O (N).

+0

. Tôi hỏi về điều gì đó nhanh hơn (nếu có thể) –

+0

Vâng. Nếu sẽ có thứ gì đó nhanh hơn, nó sẽ là std. – klm123

+0

Nó phụ thuộc. Có lẽ có một giải pháp năng động. Những người không phổ biến trong std, afaik. –

0

Bạn có thể thử (một cái gì đó không chắc chắn nếu tôi đang thiếu) sau

Nếu bạn được phép một số tiền xử lý, sau đó bạn có thể có một loạt các cực tiểu địa phương (thung lũng).

Mảng này phải được sắp xếp theo các chỉ mục tương ứng.

Khi bạn nhận được khoảng thời gian, hãy thực hiện tìm kiếm nhị phân của chỉ mục dưới trong mảng minima. Chọn cái lớn hơn trong mảng đó. nói I1

Sau đó, thực hiện tìm kiếm nhị phân của chỉ mục đã cho cao hơn trong mảng minima. Chọn cái nhỏ hơn trong mảng đó. nói I2

Nếu I2> = I1, thì ít nhất một địa phương tối thiểu tồn tại trong khoảng thời gian. Chỉ cần so sánh các giá trị tại minima trong khoảng thời gian đó và tại ranh giới để nhận câu trả lời.

Khác, không tồn tại tối thiểu địa phương trong khoảng thời gian. Trong trường hợp này, giá trị tối thiểu phải nằm ở ranh giới của khoảng thời gian. Chỉ cần so sánh hai giá trị và nhận giá trị thấp hơn.

+0

Hmm, bất kỳ bằng chứng hoặc giả nào mã? –

1

Bạn có thể sử dụng segment tree cho câu hỏi này. This là một trong những hướng dẫn tốt nhất về phân đoạn truy vấn tối thiểu cây và phạm vi.

Tôi đang thực hiện JAVA và mã tự giải thích, vui lòng cho tôi biết nếu bạn có bất kỳ nghi ngờ nào.

public class SegmentTree { 

    private int[] array; 
    private int length; 

    public static SegmentTree initialize(int[] a) { 
     return new SegmentTree(a); 
    } 

    private SegmentTree(int[] a) { 
     length = a.length - 1; 
     int l = (int) (Math.log(a.length)/Math.log(2)); 
     l = (int) (Math.pow(2, l + 1) * 2 - 1); 
     array = new int[l]; 
     initialize(a, 0, a.length - 1, 0); 
    } 

    private int initialize(int[] a, int p, int r, int index) { 
     if (p == r) { 
      array[index] = a[p]; 
      return a[p]; 
     } 
     int q = p + (r - p)/2; 
     array[index] = Math.min(initialize(a, p, q, 2 * index + 1), initialize(a, q + 1, r, 2 * index + 2)); 
     return array[index]; 
    } 

    public int findMin(int p, int r) { 
     return _findMin(p, r, 0, length, 0); 
    } 

    private int _findMin(int qs, int qe, int ss, int se, int i) { 
     if (qs <= ss && se <= qe) { 
      return array[i]; 
     } 
     if (qs > se || qe < ss) { 
      return Integer.MAX_VALUE; 
     } 
     int q = ss + (se - ss)/2; 
     return Math.min(_findMin(qs, qe, ss, q, 2 * i + 1), _findMin(qs, qe, q + 1, se, 2 * i + 2)); 
    } 

    private void print() { 
     int index = 0; 
     for (int k : array) { 
      System.out.println(index + ":" + k); 
      index++; 
     } 
    } 

    public static void main(String[] args) { 
     int[] a = {1, 34, 5, 6, 78, 5, 67, 89}; 
     SegmentTree s = initialize(a); 
     System.out.println(s.findMin(2, 4)); 
    } 
} 
+0

Sau khi đọc bài viết, mã trở nên dễ hiểu. Tuy nhiên, việc đặt tên biến 'qs, qe, ss, q' không thực sự hay trong khi giải thích (tôi cũng thích tên viết tắt của các hàm đơn giản). Ngoài ra các ý kiến ​​sẽ giúp rất nhiều. Dù sao, nhờ giải pháp logarit này, +1 :) –

Các vấn đề liên quan