2013-04-12 56 views
5

Đây là vấn đề tôi đã cân nhắc trong một thời gian.Tìm các số từ a đến b không chia hết cho x thành y

Cách nhanh nhất để tìm tất cả các số từ a đến b không chia hết cho bất kỳ số nào từ x thành y?

Hãy xem xét điều này:

Tôi muốn tìm tất cả các số từ 1 đến 10 mà không phải chia hết cho 2 đến 5. Quá trình này sẽ trở nên cực kỳ chậm nếu tôi nơi để sử dụng một cách tiếp cận tuyến tính; Giống như sau:

result = [] 
a = 1 
b = 10 
x = 2 
y = 5 
for i in range(a,b): 
    t = False 
    for j in range(x,y): 
     if i%j==0: 
      t = True 
      break 
    if t is False: 
     result.append(i) 
return result 

Có ai biết phương pháp nào làm việc này với thời gian tính toán thấp hơn giải pháp tuyến tính không?

Nếu không, ai cũng có thể xem như thế nào sức này được thực hiện nhanh hơn, như tôi trống vào thời điểm này ...

Trân trọng, John

[EDIT]

Phạm vi của số từ 0 đến> 1, e + 100

Điều này đúng với a, b, x và y

+3

Bạn có tối ưu hóa lớn (b-a), lớn b, lớn (y-x), lớn hoặc gọi nhiều lần với số lượng nhỏ? Tôi nghi ngờ câu trả lời sẽ khác nhau tùy thuộc vào những câu hỏi – Patashu

+0

Đó là một phần của vấn đề: a, b, x, y, tăng dần dần – JohnWO

+1

Bạn không muốn viết 1e100 thay vì "1, e + 100"? Nếu đây là trường hợp, sau đó sẽ rất khó để tìm thấy một phương pháp rất nhanh, như tập hợp các số không phù hợp trong bộ nhớ, hoặc thậm chí là một ổ đĩa cứng (cho đến nay). Nếu số lượng là hợp lý (nói khoảng 1e8, để chúng phù hợp với bộ nhớ), thì một cách tiếp cận nhanh có thể thu được bằng cách trao đổi bộ nhớ cho tốc độ. – EOL

Trả lời

4

Bạn chỉ cần kiểm tra các giá trị nguyên tố trong phạm vi của các ước số có thể - ví dụ, nếu một giá trị không chia hết cho 2, nó sẽ không chia hết cho bất kỳ bội số nào của 2 giá trị đó; tương tự như vậy đối với mọi số nguyên tố và số nguyên tố khác. Vì vậy, trong ví dụ của bạn, bạn có thể kiểm tra 2, 3, 5 - bạn không cần phải kiểm tra 4, bởi vì mọi thứ chia hết cho 4 phải chia hết cho 2. Do đó, cách tiếp cận nhanh hơn sẽ tính toán số nguyên tố trong bất kỳ phạm vi nào bạn quan tâm, và sau đó chỉ đơn giản là tính toán các giá trị mà chúng phân chia.

Tăng tốc khác là thêm mỗi giá trị trong phạm vi bạn quan tâm đến một số set: khi bạn thấy rằng nó có thể chia hết cho một số trong phạm vi của bạn, hãy xóa số đó khỏi tập hợp. Sau đó, bạn chỉ nên thử nghiệm các số còn lại trong tập hợp - điều này sẽ ngăn bạn kiểm tra các số nhiều lần.

Nếu chúng tôi kết hợp hai cách tiếp cận này, chúng ta thấy rằng chúng ta có thể tạo ra một set của tất cả các giá trị (như vậy trong ví dụ này, một bộ với tất cả các giá trị từ 1 đến 10), và chỉ cần loại bỏ các bội số của mỗi số nguyên tố trong dãy thứ hai của bạn từ bộ đó.

Chỉnh sửa: Như Patashu đã chỉ ra, điều này sẽ không hoàn toàn hoạt động nếu phần tử phân chia giá trị đã cho không có trong tập hợp. Để khắc phục điều này, chúng tôi có thể áp dụng thuật toán tương tự như trên: tạo một set với các giá trị [a, b], cho mỗi giá trị trong set, xóa tất cả bội số của nó. Vì vậy, đối với ví dụ được đưa ra dưới đây trong các ý kiến ​​(với [3, 6]), chúng tôi sẽ bắt đầu với 3 và loại bỏ bội số của nó trong tập hợp - như vậy 6. Do đó, các giá trị còn lại chúng ta cần kiểm tra sẽ là [3, 4, 5] đó là những gì chúng ta muốn trong trường hợp này.

Edit2: Đây là một thực sự bị hack lên, không hấp dẫn thi hành mà chưa được tối ưu hóa và có tên biến khủng khiếp:

def find_non_factors(): 
    a = 1 
    b = 1000000 
    x = 200 
    y = 1000 

    z = [True for p in range(x, y+1)] 
    for k, i in enumerate(z): 
     if i: 
      k += x 
      n = 2 
      while n * k < y + 1: 
       z[(n*k) - x] = False 
       n += 1 

    k = {p for p in range(a, b+1)} 

    for p, v in enumerate(z): 
     if v: 
      t = p + x 
      n = 1 
      while n * t < (b + 1): 
       if (n * t) in k: 
        k.remove(n * t) 
       n += 1 

    return k 

Hãy thử thực hiện ban đầu của bạn với những con số. Mất> 1 phút trên máy tính của tôi. Quá trình triển khai này mất dưới 2 giây.

+0

Điều này không đúng, ví dụ 7 * 11 không chia hết cho 2, 3, 4 hoặc 5 nhưng cũng không phải là số nguyên tố. – Patashu

+1

@Patashu Bạn đã hiểu lầm những gì tôi đã nói (mặc dù tôi đồng ý tôi đã không nói nó tốt). Tôi có nghĩa là, trong một phạm vi nói '[2, 5]' bạn chỉ cần kiểm tra '2, 3, 5' - thử nghiệm cho' 2' sẽ kiểm tra cho '4' và tất cả các bội số khác của hai. Tương tự như vậy để kiểm tra tính chia rẽ trong '[2, 10]' bạn chỉ cần kiểm tra '2, 3, 5, 7'. – Yuushi

+0

vì vậy bạn chỉ cần kiểm tra xem nó có thể chia hết cho số nguyên tố hay không là những gì anh ta nói: P –

3

Báo cáo tối ưu hóa tối ưu: Không tối ưu hóa trước khi tối ưu hóa. Bất cứ khi nào bạn cố gắng tối ưu hóa mã, hãy cấu hình nó để đảm bảo nó cần tối ưu hóa và lược tả tối ưu hóa trên cùng một loại dữ liệu mà bạn dự định sẽ được tối ưu hóa để xác nhận đó là một sự tăng tốc. Hầu như tất cả các mã không cần tối ưu hóa, chỉ để đưa ra câu trả lời đúng.

Nếu bạn đang tối ưu hóa cho x-y nhỏ và lớn một-b:

Tạo một mảng với chiều dài đó là bội số chung nhỏ nhất trong số tất cả các x, x + 1, x + 2 ... y. Ví dụ, đối với 2, 3, 4, 5, nó sẽ là 60, không phải 120.

Bây giờ điền mảng này với booleans - false ban đầu cho mỗi ô, sau đó cho mỗi số trong xy, điền tất cả các mục trong mảng là bội số của con số đó với đúng.

Bây giờ cho mỗi số trong a-b, chỉ mục vào mảng mảng mảng modlength và nếu nó là đúng, bỏ qua khác nếu nó là sai, trả về.

Bạn có thể làm điều này nhanh hơn một chút bằng cách xóa từ bạn x thành y số nguyên tố mà mở rộng yếu tố chính là supersets nghiêm ngặt của các số nguyên tố mở rộng của các số khác. Ý tôi là - nếu bạn có 2, 3, 4, 5, 4 là 2 * 2 một bộ siêu nghiêm ngặt của 2 để bạn có thể loại bỏ nó và bây giờ chiều dài mảng của chúng tôi chỉ là 30. Đối với một cái gì đó như 3, 4, 5, 6 tuy nhiên, 4 là 2 * 2 và 6 là 3 * 2 - 6 là một bội số của 3 vì vậy chúng tôi loại bỏ nó, nhưng 4 không phải là một superset của tất cả mọi thứ vì vậy chúng tôi giữ nó trong. LCM là 3 * 2 * 2 * 5 = 60 Làm việc như thế này sẽ làm tăng tốc độ của chính mình cho ab lớn, và bạn có thể không cần phải đi theo hướng mảng nếu đó là tất cả những gì bạn cần.

Ngoài ra, hãy nhớ rằng nếu bạn không sử dụng toàn bộ kết quả của hàm mỗi lần - giống như đôi khi bạn chỉ quan tâm đến giá trị thấp nhất - hãy viết nó làm máy phát chứ không phải là một hàm. Bằng cách đó bạn có thể gọi nó cho đến khi bạn có đủ số và sau đó dừng lại, tiết kiệm thời gian.

+0

Cảm ơn bạn đã trả lời! Điều này nhanh hơn nhiều so với ví dụ được cung cấp khi bạn nói: "tối ưu hóa cho các x-y nhỏ và lớn a-b" Sự cố phát sinh khi phạm vi của x-y trở nên lớn. Chỉ để không có sự nhầm lẫn phát sinh: Những gì bạn đã xác định x-y là, tôi đã xác định là a-b. – JohnWO

+0

@ user2272969 Tôi nên sử dụng cùng một lược đồ đặt tên như bạn. – Patashu

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