To improve the time complexity of your program and make it more efficient, you can consider the following optimizations:
Instead of iterating up to the number itself, you can limit the first loop to the square root of the number. This reduces the number of iterations required to find the factors.
Rather than storing all the factors in a list, you can calculate the count of factors directly while iterating. This eliminates the need for the factors list and the subsequent calculation of total_len.
Instead of removing elements from the list, you can create a new list that only includes the non-perfect square factors. This avoids the need for nested loops and improves efficiency.
Here's a version of your program with these optimizations:
import math
number = int(input())
perfectSquares = []
count = 0
# Find perfect square numbers
for i in range(2, int(math.sqrt(number)) + 1):
if i * i <= number:
perfectSquares.append(i * i)
# Find the total number of factors and count perfect square factors
for i in range(1, number):
if number % i == 0:
count += 1
for j in perfectSquares:
if i % j == 0:
count -= 1
break
# Print the total count of square-free numbers
total_len = number - count
print(total_len)
By implementing these optimizations, you can reduce the number of iterations and improve the time complexity of your program.