Skip to content

Commit 1b90fe5

Browse files
committed
feat(dsa): fast and slow pointers approach to is happy number
1 parent d18bf13 commit 1b90fe5

18 files changed

+259
-1
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Happy Number
2+
3+
Write an algorithm to determine if a number n is a happy number.
4+
5+
We use the following process to check if a given number is a happy number:
6+
7+
- Starting with the given number n, replace the number with the sum of the squares of its digits.
8+
- Repeat the process until:
9+
- The number equals 1, which will depict that the given number n is a happy number.
10+
- The number enters a cycle, which will depict that the given number n is not a happy number.
11+
12+
Return TRUE if n is a happy number, and FALSE if not.
13+
14+
## Examples
15+
16+
### Sample Example 1
17+
18+
![Sample Example 1.1](example_1_1.png)
19+
![Sample Example 1.2](example_1_2.png)
20+
![Sample Example 1.3](example_1_3.png)
21+
22+
### Sample Example 2
23+
24+
![Sample Example 2.1](example_2_1.png)
25+
![Sample Example 2.2](example_2_2.png)
26+
![Sample Example 2.3](example_2_3.png)
27+
28+
## Solution Example
29+
30+
Below shows an example using Floyd's Cycle Detection Algorithm or Tortoise and Hare algorithm to detect a cycle
31+
for the number 2.
32+
33+
![Solution Example 1](solution_example_1.png)
34+
![Solution Example 2](solution_example_2.png)
35+
![Solution Example 3](solution_example_3.png)
36+
![Solution Example 4](solution_example_4.png)
37+
![Solution Example 5](solution_example_5.png)
38+
![Solution Example 6](solution_example_6.png)
39+
![Solution Example 7](solution_example_7.png)
40+
![Solution Example 8](solution_example_8.png)
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
def is_happy_number(n: int) -> bool:
2+
"""
3+
Checks if an unsigned integer is a happy number
4+
5+
A happy number is defined by the following process:
6+
- Replace the number by the sum of the squares of its digits.
7+
- Repeat the process until the number becomes 1 (happy number)
8+
or a cycle is detected (not a happy number).
9+
10+
This uses a set to store already seen numbers which consumes extra space. But since the numbers may not be too
11+
large, using a set might be straightforward and easy to implement
12+
13+
While this approach works well for small numbers, we might have to perform several computations for larger numbers
14+
to get the required result. So, it might get infeasible for such cases. The time complexity of this approach is
15+
O(log(n)). The space complexity is O(log(n)) since we're using additional space to store our calculated sums.
16+
17+
Args:
18+
n (int): a positive integer
19+
Returns:
20+
bool: True if n is a happy number, False otherwise
21+
"""
22+
23+
def get_next(number: int) -> int:
24+
total_sum = 0
25+
while number > 0:
26+
digit = number % 10
27+
total_sum += digit * digit
28+
number //= 10
29+
return total_sum
30+
31+
seen = set()
32+
while n != 1 and n not in seen:
33+
seen.add(n)
34+
n = get_next(n)
35+
36+
return n == 1
37+
38+
def is_happy_number_2(n: int) -> bool:
39+
"""
40+
Checks if an unsigned integer is a happy number
41+
42+
To determine whether a number is a happy number, it is iteratively replaced by the sum of the squares of its digits,
43+
forming a sequence of numbers. This sequence either converges to 1 (if the number is happy) or forms a cycle
44+
(if the number is not happy). We use the fast and slow pointers technique to detect such cycles efficiently.
45+
This technique involves advancing two pointers through the sequence at different speeds: one moving one step at a
46+
time and the other two at a time.
47+
48+
The pointer moving slower is initialized to the given number, and the faster one starts at the sum of the squared
49+
digits of the given number. Then, in each subsequent iteration, the slow pointer updates to the sum of squared
50+
digits of itself, while the fast pointer advances two steps ahead: first by updating to the sum of squared digits
51+
of itself and then to the sum of squared digits of this recently calculated sum. If the number is happy, the fast
52+
pointer will eventually reach 1.
53+
54+
However, if the number is not happy, indicating the presence of a cycle in the sequence, both pointers will
55+
eventually meet. This is because, in the non-cyclic part of the sequence, the distance between the pointers
56+
increases by one number in each iteration. Once both pointers enter the cyclic part, the faster pointer starts
57+
closing the gap on the slower pointer, decreasing the distance by one number in each iteration until they meet.
58+
This way, we can efficiently determine whether a number is a happy number or not.
59+
60+
The time complexity for this algorithm is O(log(n)), where n is the input number.
61+
62+
The worst case time complexity of this algorithm is given by the case of a non-happy number, since it gets stuck in
63+
a cycle, whereas a happy number quickly converges to 1. Let’s first calculate the time complexity of the Sum Digits
64+
function. Since we are calculating the sum of all digits in a number, the time complexity of this function is
65+
O(log(n)), because the number of digits in the number n log10n.
66+
67+
68+
Space complexity is O(1)
69+
70+
Args:
71+
n (int): a positive integer
72+
Returns:
73+
bool: True if n is a happy number, False otherwise
74+
"""
75+
76+
def sum_of_squared_digits(number: int) -> int:
77+
"""
78+
Helper function that calculates the sum of squared digits
79+
"""
80+
total_sum = 0
81+
# an alternative
82+
# while number > 0:
83+
# number, digit = divmod(number, 10)
84+
# total_sum += digit ** 2
85+
while number > 0:
86+
digit = number % 10
87+
total_sum += digit * digit
88+
number //= 10
89+
return total_sum
90+
91+
slow_pointer = n
92+
fast_pointer = sum_of_squared_digits(n)
93+
94+
while fast_pointer != 1 and slow_pointer != fast_pointer:
95+
slow_pointer = sum_of_squared_digits(slow_pointer)
96+
fast_pointer = sum_of_squared_digits(sum_of_squared_digits(fast_pointer))
97+
98+
if fast_pointer == 1:
99+
return True
100+
101+
return False
38.6 KB
Loading
39.1 KB
Loading
40.4 KB
Loading
39.9 KB
Loading
39.3 KB
Loading
49.7 KB
Loading
33.5 KB
Loading
41 KB
Loading

0 commit comments

Comments
 (0)