Skip to content

Commit 6b00d0e

Browse files
committed
feat(algorithms, two-pointers): triangle numbers
1 parent c95ac53 commit 6b00d0e

31 files changed

+155
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Triangle Numbers
2+
3+
Write a function to count the number of triplets in an integer array nums that could form the sides of a triangle. For
4+
three sides to form a valid triangle, the sum of any two sides must be greater than the third side. The triplets do not
5+
need to be unique.
6+
7+
## Examples
8+
9+
```text
10+
Input:
11+
nums = [11,4,9,6,15,18]
12+
13+
Output:
14+
10
15+
16+
Explanation: Valid combinations are...
17+
18+
4, 15, 18
19+
6, 15, 18
20+
9, 15, 18
21+
11, 15, 18
22+
9, 11, 18
23+
6, 11, 15
24+
9, 11, 15
25+
4, 6, 9
26+
```
27+
28+
## Solution
29+
30+
In order for a triplet to be valid lengths of a triangle, the sum of any two sides must be greater than the third side.
31+
By sorting the array, we can leverage the two-pointer technique to count all valid triplets in O(n2) time and O(1) space.
32+
The key to this question is realizing that if we sort three numbers from smallest to largest (say a ≤ b ≤ c), we only
33+
need to check if a + b > c. If this condition holds, the other two conditions (a + c > b and b + c > a) are automatically
34+
satisfied because c ≥ b and b ≥ a. For example, with 4, 8, 9, if 4 + 8 > 9 is true, then we have a valid triplet.
35+
36+
![Solution 1](./images/solutions/triangle_numbers_solution_1.png)
37+
38+
But not only that, triplets where the smallest number is between 4 and 8 are also valid triplets.
39+
40+
![Solution 2](./images/solutions/triangle_numbers_solution_2.png)
41+
42+
This means that if we sort the input array, and then iterate from the end of the array to the beginning, we can use the
43+
two-pointer technique to efficiently count all valid triplets.
44+
45+
![Solution 3](./images/solutions/triangle_numbers_solution_3.png)
46+
47+
The pointers i, left, and right represent the current triplet we are considering. If nums[left] + nums[right] > nums[i]
48+
then we know there are a total of right - left valid triplets, since all triplets between left and right are also valid
49+
triplets. We can then decrement right to check for the valid triplets that can be made by decreasing the middle value.
50+
51+
![Solution 4](./images/solutions/triangle_numbers_solution_4.png)
52+
![Solution 5](./images/solutions/triangle_numbers_solution_5.png)
53+
![Solution 6](./images/solutions/triangle_numbers_solution_6.png)
54+
![Solution 7](./images/solutions/triangle_numbers_solution_7.png)
55+
56+
When nums[left] + nums[right] < nums[i], we know that all triplets between left and right are also invalid, so we
57+
increment left to look for a larger smallest value.
58+
59+
![Solution 8](./images/solutions/triangle_numbers_solution_8.png)
60+
61+
Each time left and right cross, we decrement i and reset left and right to their positions at opposite ends of the array.
62+
This happens until i is less than 2, at which point we have counted all valid triplets.
63+
64+
![Solution 9](./images/solutions/triangle_numbers_solution_9.png)
65+
![Solution 10](./images/solutions/triangle_numbers_solution_10.png)
66+
![Solution 11](./images/solutions/triangle_numbers_solution_11.png)
67+
![Solution 12](./images/solutions/triangle_numbers_solution_12.png)
68+
![Solution 13](./images/solutions/triangle_numbers_solution_13.png)
69+
![Solution 14](./images/solutions/triangle_numbers_solution_14.png)
70+
![Solution 15](./images/solutions/triangle_numbers_solution_15.png)
71+
![Solution 16](./images/solutions/triangle_numbers_solution_16.png)
72+
![Solution 17](./images/solutions/triangle_numbers_solution_17.png)
73+
![Solution 18](./images/solutions/triangle_numbers_solution_18.png)
74+
![Solution 19](./images/solutions/triangle_numbers_solution_19.png)
75+
![Solution 20](./images/solutions/triangle_numbers_solution_20.png)
76+
![Solution 21](./images/solutions/triangle_numbers_solution_21.png)
77+
![Solution 22](./images/solutions/triangle_numbers_solution_22.png)
78+
![Solution 23](./images/solutions/triangle_numbers_solution_23.png)
79+
![Solution 24](./images/solutions/triangle_numbers_solution_24.png)
80+
![Solution 25](./images/solutions/triangle_numbers_solution_25.png)
81+
![Solution 26](./images/solutions/triangle_numbers_solution_26.png)
82+
![Solution 27](./images/solutions/triangle_numbers_solution_27.png)
83+
![Solution 28](./images/solutions/triangle_numbers_solution_28.png)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from typing import List
2+
3+
4+
def triangle_number(heights: List[int]) -> int:
5+
"""
6+
Finds the count of valid triangles that can be formed from the given input of numbers. A valid triangle is a triangle
7+
which has any two sides whose sum is greater than the third side. This assumes that it is okay to manipulate the
8+
input list. Therefore callers of this function should be aware that the input list is manipulated in place.
9+
10+
Args:
11+
heights (list): list of integers that represent sides of a triangle
12+
Returns:
13+
int: number of valid triangles that can be formed
14+
"""
15+
# If there are no heights, or we have an empty list, return 0 early as no valid triangles can be formed here.
16+
if not heights:
17+
return 0
18+
19+
# Sorts the heights in place. This incurs a time complexity cost of O(n log(n)) and space cost of O(n) as this sorting
20+
# requires temporary storage using Python's timsort
21+
heights.sort()
22+
23+
# Keeps track of number of valid triangles that can be formed
24+
count = 0
25+
26+
# Iterate through the list starting from the back, idx will be at the last position, this will be the third pointer
27+
for idx in range(len(heights) - 1, 1, -1):
28+
# Initialize the two pointers to keep track of the other two indices that will point to the two other numbers that
29+
# can form a valid triangle.
30+
left = 0
31+
right = idx - 1
32+
33+
# This is a micro-optimization to get the largest side and use it in the loop below
34+
largest_side = heights[idx]
35+
36+
while left < right:
37+
# A valid triplet is found by satisfying the condition a + b > c. If this condition holds, then the other
38+
# two conditions hold as well, a + c > b and b + c > a.
39+
is_valid_triplet = heights[left] + heights[right] > largest_side
40+
if is_valid_triplet:
41+
# The numbers between the right and left pointers form valid triplets with the number at the idx position
42+
# we find all the possible triplets(triangles) that can be formed by finding the difference.
43+
count += right - left
44+
# we decrement right to check if there are valid triplets that can be formed by decreasing the middle valid
45+
right -= 1
46+
else:
47+
# Increase the left to find the next maximum minimum number that can form a valid triplet
48+
left += 1
49+
50+
# return the count of the triangles that can be formed
51+
return count
15.7 KB
Loading
34.2 KB
Loading
30.8 KB
Loading
27.3 KB
Loading
30.9 KB
Loading
30.8 KB
Loading
37.1 KB
Loading
31 KB
Loading

0 commit comments

Comments
 (0)