Cho em hỏi là theo như lí thuyết sàng nguyên tố Eratosthenes thì em code được như thế này . Code chạy nhanh hơn thuật toán kiểm tra từng số , nhưng mà với số lớn cỡ 2000000 thì rất lâu. Mấy anh có thể giúp em tối ưu hơn
# em là sv năm nhất , nhà trường dạy python3
n=int(input())
a=[2]
for i in range(3, n, 2):
a.append(i)
for m in a:
for n in a:
if n % m ==0 and n!=m:
a.remove(n)
print(a)
theo như wikipedia là :
Bước 1: Tạo 1 danh sách các số tự nhiên liên tiếp từ 2 đến n: (2, 3, 4,…, n).
Bước 2: Giả sử tất cả các số trong danh sách đều là số nguyên tố. Trong đó, p = 2 là số nguyên tố đầu tiên.
Bước 3: Tất cả các bội số của p: 2p, 3p, 4p,… sẽ bị đánh dấu vì không phải là số nguyên tố.
Bước 4: Tìm các số còn lại trong danh sách mà chưa bị đánh dấu và phải lớn hơn p. Nếu không còn số nào, dừng tìm kiếm. Ngược lại, gán cho p giá trị bằng số nguyên tố tiếp theo và quay lại bước 3.
m chạy tới n, trong khi đúng ra m chỉ cần chạy tới căn(n) là đủ
a.remove(n): 1 lần bỏ 1 số n ra khỏi mảng a phải đôn các số phía sau n lên trước 1 vị trí, hay có thể hiểu đây là 1 vòng for nữa. Vd: 2 3 4 5 6 7 bỏ 4 ra thì phải dồn 5 6 7 lên trước thành 2 3 5 6 7. Nếu phía sau có 2 triệu số thì đôn lên 2 triệu lần…
bước 3 ko đúng vì n phải nhảy p lần, trong khi for n in a nhảy từng bước một và bị buộc phải xét xem n có chia hết cho m hay ko, trong khi nhảy 2p, 3p, 4p, v.v… ko cần xét xem n có chia hết cho p hay ko vì n đã là bội của p. Ngoài ra “đánh dấu” loại phải gọn nhẹ, ko có dồn mảng. Ngoài ra nữa ta chỉ xét các bội số từ p*p, (p+1)*p, v.v… chứ đừng xét từ 2p vì 2,3,…,p-1 đã bị loại rồi.
@hungaya : có xét x có chia hết cho p hay ko thì ko phải rồi.
from math import sqrt
N = int(input())
sqrtN = int(sqrt(N))
sieve = [True] * (N+1) # sàng nguyên tố: nếu sieve[x] == True thì x là số nguyên tố
sieve[0] = sieve[1] = False # ko cần cũng ko sao, viết luôn cho nó đúng nghĩa
for p in range(2, sqrtN+1): # p chỉ chạy tới căn(N)
if not sieve[p]: continue # chỉ tiếp tục bước 3 nếu p là số nguyên tố
for n in range(p*p, N+1, p): # n chạy từ p*p tới N, nhảy p lần nên n luôn là bội của p, ko cần xét n % p == 0
sieve[n] = False # đánh dấu ko phải là số nguyên tố: chỉ tốn O(1)
for p in range(2, N+1):
if sieve[p]:
print(p, end=' ')