2013-07-12 73 views
5

Tôi gặp sự cố này "Triển khai phương thức này để trả về tổng của hai số lớn nhất trong một mảng nhất định".Độ phức tạp của thuật toán

tôi giải quyết nó theo cách này:

public static int sumOfTwoLargestElements(int[] a) { 

    int firstLargest = largest(a, 0, a.length-1); 

    int firstLarge = a[firstLargest]; 
    a[firstLargest] = -1; 

    int secondLargest = largest(a, 0, a.length-1); 

    return firstLarge + a[secondLargest]; 
} 

private static int largest(int s[], int start , int end){ 

    if (end - start == 0){ 

     return end; 
    } 


    int a = largest(s, start, start + (end-start)/2) ; 
    int b = largest(s, start + (end-start)/2+1 , end); 
    if(s[a] > s[b]) { 

     return a; 
    }else { 

     return b; 
    } 

} 

Giải thích: Tôi thực hiện một phương pháp 'largeset'. Phương thức này chịu trách nhiệm lấy số lớn nhất trong một mảng nhất định.

Tôi gọi phương thức kéo lần trong cùng một mảng. Cuộc gọi đầu tiên sẽ nhận được số lớn nhất đầu tiên. Tôi đặt nó sang một bên thành biến và tôi thay thế nó bằng số '-1' vào mảng. Sau đó, tôi gọi lần thứ hai là medhod lớn nhất.

Một số người có thể cho tôi biết sự phức tạp của bản ngã này là gì? vui lòng

+5

Bạn có thể tìm thấy cả hai con số trong đầu tiên vượt qua và tha đèo thứ hai. Nó sẽ không thay đổi sự phức tạp nhưng nó sẽ chạy nhanh hơn. :-) – assafmo

+0

+1 cho nhận xét ở trên. Ngoài ra nếu nó chỉ là một danh sách các con số, thì có nhiều cách giải khác nhau ... nếu bạn sử dụng một cơ chế như đếm số vv với không gian thừa không đáng kể và độ phức tạp thời gian O (n) ... – dharam

+0

phức tạp là của người đọc trong tương lai của mã này, thời gian họ dành cho việc tìm ra cách thức hoạt động này, khi một thuật toán đơn giản hơn nhiều sẽ thực hiện công việc. Không có lợi ích rõ ràng để đệ quy, hoặc lý do tại sao hai đi qua các thiết lập là cần thiết.Và thuật toán về cơ bản bị hỏng (trả về kết quả không chính xác) khi hai số nguyên lớn nhất trong mảng đều nhỏ hơn -1. Accckkk! – spencer7593

Trả lời

11

Độ phức tạp của thuật toán là O(n).

phức tạp Mỗi cuộc gọi đệ quy là thực sự:

f(n) = 2*f(n/2) + CONST 

Nó rất dễ dàng để xem (bằng cảm ứng) mà f(n) <= CONST'*n - và do đó nó là O(n).

Độ phức tạp của không gian là O(logN) - bởi vì đây là độ sâu tối đa của đệ quy - do đó bạn phân bổ bộ nhớ O(logN) trên ngăn xếp cuộc gọi.


(1) Nếu bạn sử dụng f(n) = 2*n*CONST - CONST bạn nhận được:

f(n) = 2*f(n/2) + CONST = (h.i.) 2*(2*CONST*n/2 - CONST) + CONST = 
= 2*n*CONST - 2CONST + CONST = 2*n*CONST - CONST 

(Kiểm tra cơ sở được là trái như tập thể dục cho người đọc)

+0

Vì vậy, f (0) có độ phức tạp âm? Tôi nghĩ rằng sự phức tạp là O (2^n * log n). –

+0

@undur_gongor Công thức không áp dụng cho các giá trị cơ bản hoặc thấp hơn, rõ ràng (đây là điểm cảm ứng, chúng tôi chứng minh từ một số điểm trở lên, tất cả các cược được đặt bên dưới nó). Các cơ sở nên được cho 'f (1)', và như đã đề cập bên trái như là một tập thể dục. – amit

+0

@undur_gongor: Và, chính xác - vì chúng tôi chỉ sử dụng bình đẳng trong bằng chứng, chúng tôi đã chỉ ra rằng 'f (n)' nằm trong 'Theta (n)' - vì vậy 'O (n)' là một tiệm cận tiệm cận bị ràng buộc. – amit

3

Sự phức tạp của thuật toán sẽ được đo là O(n).

Nhưng câu trả lời thực sự là thuật toán của bạn là WAY phức tạp hơn và tốn kém hơn về tài nguyên máy hơn mức cần thiết. Và nó tốn kém hơn về việc ai đó đọc mã của bạn và tìm hiểu xem nó đang làm gì.

Sự phức tạp của thuật toán của bạn thực sự nên vào thứ tự của:

public static int sumOfTwoLargestElements(int[] a) { 

    //TODO handle case when argument is null, 
    //TODO handle case when array has less than two non-null elements, etc. 

    int firstLargest = Integer.MIN_VALUE; 
    int secondLargest = Integer.MIN_VALUE; 
    for (int v : a) { 
     if (v > firstLargest) { 
      secondLargest = firstLargest; 
      firstLargest = v; 
     } else if (v > secondLargest) secondLargest = v; 
    } 
    //TODO handle case when sum exceeds Integer.MAX_VALUE; 
    return firstLargest + secondLargest; 
} 
+2

Tôi nghĩ bạn sẽ cần 'if (v> firstLargest) {secondLargest = firstLargest; firstLargest = v}; ' – Rhialto

0

Mục đích của tôi là thực hiện một thuật toán cho 'lớn' với độ phức tạp ít hơn O (n). Đó là lý do tại sao tôi không muốn làm vòng lặp for. Cám ơn câu trả lời của bạn :)

+2

Không thể làm tốt hơn O (n) trên một mảng chưa được sắp xếp. Nó chắc chắn có thể làm tốt hơn mã của bạn - spencer là một ví dụ tốt. Bạn chỉ cần thực hiện một lần thông qua mảng, và tất nhiên sửa đổi mảng chỉ để có được một số liệu thống kê là không có thật. Điều gì sẽ xảy ra nếu mảng đã cho là chỉ đọc? –

0

Các reccurence cho phương pháp 'lớn nhất' là:

 _ 
f(n) = ! 
     ! 1  n = 1 
     ! 2f(n/2) n >=2 
     !_ 

If we experiment some few cases, we notice that 

f(n) = 2^log(n) When n is power of 2  Rq:Log base 2 

Proof: 

By induction, 

f(1) = 2^log(1) = 2^log(2^0) = 1 

We suppose that f(n) = 2^log(n)=n 

We show f(2n) = 2^log(2n)= 2n^log(2)=2n 

f(2n) = 2*f(2n/2) = 2*f(n) 
        = 2*2^log(n) 
        = 2^log(n) + 1 
        = 2^log(n) + log(2^0) 
        = 2^log(2n) 
        = 2n^log(2) by log properties 
        = 2n 
Then f(n) = 2^log(n)=n When n is power of2-smooth function f(2n) < c f(n). it follows smooth function properties that **f(n) = theta of n** 
Các vấn đề liên quan