-
Notifications
You must be signed in to change notification settings - Fork 95
/
310.py
77 lines (57 loc) · 1.92 KB
/
310.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
"""
Problem:
Write an algorithm that finds the total number of set bits in all integers between 1
and N.
"""
from math import log
from time import perf_counter
def get_set_bits(num: int) -> int:
bin_num = bin(num)[2:]
return sum([int(digit) for digit in bin_num])
def get_total_set_bits(N: int) -> int:
result = 0
for i in range(1, N + 1):
result += get_set_bits(i)
return result
def get_total_set_bits_optimized(N: int) -> int:
if N < 1:
return 0
# Find the greatest power of 2 less than or equal to n
exp = int(log(N, 2))
pow = 2**exp
# Initializations
extra_ones = 0
sum = 0
while True:
# Count the bits of the pow-many numbers starting from where we left off (or 1, if the first iteration)
# The logic here is that each of the least significant exp-many bits occurs in half those numbers, i.e. pow/2 times. Plus all the more significant bits that are constantly set throughout
sum += pow // 2 * exp + pow * extra_ones
# All numbers above this will have an additional bit set
extra_ones += 1
# If n is a power of two, add its own bits and exit
if pow == N:
sum += extra_ones
break
# Now set n to be the remainder after counting pow numbers...
N -= pow
# ...and calculate the greatest power of 2 that is less than or equal to our new n
while pow > N:
pow //= 2
exp -= 1
return sum
if __name__ == "__main__":
for i in list(range(6)) + [10**6]:
for f in [get_total_set_bits, get_total_set_bits_optimized]:
start = perf_counter()
result = f(i)
end = perf_counter()
print(f"{result} ({end-start:.3} sec)")
"""
SPECS:
get_total_set_bits:
TIME COMPLEXITY: O(n x log(n))
SPACE COMPLEXITY: O(1)
get_total_set_bits_optimized:
TIME COMPLEXITY: O(log(n))
SPACE COMPLEXITY: O(1)
"""