2016-10-11 17 views
5

Tôi hiện đang cố gắng giải quyết ProjectEuler problem và tôi đã gỡ mọi thứ, ngoại trừ tốc độ. Tôi gần như chắc chắn lý do chương trình thực hiện rất chậm là do các vòng lồng nhau. Tôi rất thích một số lời khuyên về cách tăng tốc độ này. Tôi là một lập trình viên mới, vì vậy tôi không quen thuộc với nhiều phương pháp/chủ đề nâng cao hơn.Làm cách nào để tăng tốc chương trình này?

public class Problem12 { 

    public static void main(String[] args) { 
     int num; 

     for (int i = 1; i < 15000; i++) { 
      num = i * (i + 1)/2; 
      int counter = 0; 

      for (int x = 1; x <= num; x++) { 
       if (num % x == 0) { 
        counter++; 
       } 
      } 
      System.out.println("[" + i + "] - " + num + " is divisible by " + counter + " numbers."); 
     } 
    } 
} 

EDIT: Dưới đây là mã mới nhanh hơn theo cấp số nhân. Loại bỏ các dòng in liên tục cũng như để tăng tốc độ nó lên nhiều hơn.

public class Problem12 { 

    public static void main(String[] args) { 
     int num; 

     outerloop: 
     for (int i = 1; i < 25000; i++) { 
      num = i * (i + 1)/2; 
      int counter = 0; 

      double root = Math.sqrt(num); 
      for (int x = 1; x < root; x++) { 
       if (num % x == 0) { 
        counter += 2; 
        if (counter >= 500) { 
         System.out.println("[" + i + "] - " + num + " is divisible by " + counter + " numbers."); 
         break outerloop; 
        } 
       } 
      } 
     } 
    } 
} 
+1

Hãy thử sử dụng ngôn ngữ nhanh hơn như C và thử sử dụng bithifts thay vì chia và nhân, nếu chúng có sẵn trong Java –

+0

Thuật toán này có hoạt động không? Vì vậy, nếu như 'i = 3' sau đó' num = 6' và sau đó là 'counter = 4' không chính xác là – afsafzal

+4

@ShaheAnsar thì bạn có thể giả định rằng C nhanh hơn Java như thế nào, nếu bạn không biết đủ để biết bithifts được hỗ trợ? – njzk2

Trả lời

5

Đối với người mới bắt đầu, khi nhìn vào ước, bạn không bao giờ cần phải đi xa hơn so với căn bậc hai của số lượng, bởi vì mỗi ước dưới căn bậc hai có tương đương ở trên.

n = a * b => a <= sqrt(n) or b <= sqrt(n) 

Sau đó, bạn cần phải đếm phía bên kia của bộ phận:

double root = Math.sqrt(num); 
for (int x = 1; x < root; x++) { 
    if (num % x == 0) { 
     counter += 2; 
    } 
} 

Các căn bậc hai là đặc biệt bởi vì nó chỉ tính một lần nếu nó là số nguyên:

if ((double) ((int) root) == root) { 
    counter += 1; 
} 
+0

Điều này đã làm được điều này. Tuy nhiên, tôi không chắc chắn làm thế nào. Bạn có phiền hơn một chút về lý do tại sao nó hoạt động không? – jxshu

+1

mỗi ước tính hoạt động như một cặp, đó là lý do chúng tôi tính hai lần. Đối với mỗi cặp, một phần tử nằm bên dưới căn bậc hai, phần tử kia ở trên. Điều này rất dễ thấy: nếu cả hai phần tử ở trên, kết quả cũng ở trên. Nếu cả hai dưới đây, kết quả là dưới đây là tốt. Ví dụ: '10 = 2 * 5 = 1 * 10'. 2 và 1 dưới 3.16, 5 và 10 ở trên. – njzk2

+0

althoug, tôi đã sai về việc không có số tam giác _and_ vuông, chỉnh sửa ngay bây giờ – njzk2

0

Bạn chỉ cần phải xác định số lượng. p^a * q^b * r^c(a+1)*(b+1)*(c+1) ước. Dưới đây là một số triển khai cơ bản sử dụng ý tưởng này:

static int Divisors(int num) { 
    if (num == 1) { 
     return 1; 
    } 

    int root = (int) Math.sqrt(num); 
    for (int x = 2; x <= root; x++) { 
     if (num % x == 0) { 
      int c = 0; 
      do { 
       ++c; 
       num /= x; 
      } while (num % x == 0); 
      return (c + 1) * Divisors(num); 
     } 
    } 

    return 2; 
} 

public static void test500() { 
    int i = 1, num = 1; 
    while (Divisors(num) <= 500) { 
     num += ++i; 
    } 

    System.out.println("\nFound: [" + i + "] - " + num); 
} 
Các vấn đề liên quan