Skip to content

Commit 3463749

Browse files
Frequency map approach for finding lucky number
1 parent eba4f1f commit 3463749

File tree

3 files changed

+197
-0
lines changed

3 files changed

+197
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package array.lucky_integer;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
/**
7+
* Solves the "Find Lucky Integer" problem using a HashMap to count frequencies.
8+
*
9+
* <p>This approach first iterates through the array to build a frequency map of all
10+
* numbers, then iterates through the map to find the largest number whose value
11+
* matches its frequency.
12+
*/
13+
public class FrequencyMap {
14+
15+
/**
16+
* Finds the largest lucky integer in an array.
17+
*
18+
* <p>A lucky integer is an integer that has a frequency in the array equal to its value.
19+
* This method uses a two-pass approach:
20+
* <ol>
21+
* <li>Build a frequency map of all numbers in the input array.</li>
22+
* <li>Iterate through the map to find the largest key that equals its value.</li>
23+
* </ol>
24+
*
25+
* <p><b>Complexity:</b>
26+
* <ul>
27+
* <li>Time: O(N), where N is the number of elements in {@code arr}. The first loop
28+
* takes O(N), and the second loop takes O(U), where U is the number of unique
29+
* elements (U &le; N).
30+
* <li>Space: O(U), to store the unique elements in the frequency map.
31+
* </ul>
32+
*
33+
* @param arr The input array of integers. Constraints: 1 &le; arr.length &le; 500,
34+
* 1 &le; arr[i] &le; 500.
35+
* @return The largest lucky integer in the array, or -1 if none exists.
36+
*/
37+
public int findLucky(int[] arr) {
38+
// Step 1: Create a frequency map to count occurrences of each number.
39+
// The key is the number from the array, and the value is its frequency.
40+
Map<Integer, Integer> freqMap = new HashMap<>();
41+
for (int num : arr) {
42+
// For each number, increment its count in the map.
43+
// getOrDefault handles the case where the number is seen for the first time.
44+
freqMap.put(num, freqMap.getOrDefault(num, 0) + 1);
45+
}
46+
47+
// Step 2: Find the largest lucky integer.
48+
// Initialize the result to -1, which will be returned if no lucky integer is found.
49+
int lucky = -1;
50+
51+
// Iterate through each entry (number and its count) in the frequency map.
52+
for (var entry : freqMap.entrySet()) {
53+
int num = entry.getKey();
54+
int count = entry.getValue();
55+
56+
// A number is "lucky" if its value is equal to its frequency.
57+
// We also check if this lucky number is greater than the one we've already found.
58+
if (num == count && num > lucky) {
59+
// If it is, update our result to this new, larger lucky number.
60+
lucky = num;
61+
}
62+
}
63+
64+
// Return the largest lucky number found, or -1 if none existed.
65+
return lucky;
66+
}
67+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Provides solutions for the "Find Lucky Integer in an Array" problem.
3+
*
4+
* <p>The problem is defined as follows: Given an array of integers {@code arr},
5+
* a "lucky integer" is an integer whose frequency in the array is equal to its value.
6+
*
7+
* <p>The goal of the implementations in this package is to find and return the
8+
* largest lucky integer from the input array. If no such integer exists, the
9+
* implementations will return -1.
10+
*
11+
* <p>For example, in the array {@code [2, 2, 3, 4]}, the number 2 is a lucky
12+
* integer because it appears 2 times. In {@code [1, 2, 2, 3, 3, 3]}, both 1 and 3
13+
* are lucky integers, and the correct return value would be 3, as it is the largest.
14+
*
15+
* <h3>Constraints:</h3>
16+
* <ul>
17+
* <li>{@code 1 <= arr.length <= 500}</li>
18+
* <li>{@code 1 <= arr[i] <= 500}</li>
19+
* </ul>
20+
*
21+
* @version 1.0
22+
* @see <a href="https://leetcode.com/problems/find-lucky-integer-in-an-array/">LeetCode 1394: Find Lucky Integer in an Array</a>
23+
* @since 1.0
24+
*/
25+
package array.lucky_integer;
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package array.lucky_integer;
2+
3+
import org.junit.jupiter.api.BeforeEach;
4+
import org.junit.jupiter.api.DisplayName;
5+
import org.junit.jupiter.api.Test;
6+
7+
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
9+
/**
10+
* Test suite for the {@link FrequencyMap} class.
11+
*/
12+
class FrequencyMapTest {
13+
14+
private FrequencyMap frequencyMap;
15+
16+
@BeforeEach
17+
void setUp() {
18+
frequencyMap = new FrequencyMap();
19+
}
20+
21+
@Test
22+
@DisplayName("Should return the largest lucky integer when multiple exist")
23+
void findLucky_whenMultipleLuckyIntegersExist_shouldReturnLargest() {
24+
int[] arr = {1, 2, 2, 3, 3, 3};
25+
assertEquals(3, frequencyMap.findLucky(arr), "The largest lucky integer is 3, as 1 and 3 are both lucky.");
26+
}
27+
28+
@Test
29+
@DisplayName("Should return a single lucky integer when one exists")
30+
void findLucky_whenOneLuckyIntegerExists_shouldReturnIt() {
31+
int[] arr = {2, 2, 3, 4};
32+
assertEquals(2, frequencyMap.findLucky(arr), "The only lucky integer is 2.");
33+
}
34+
35+
@Test
36+
@DisplayName("Should return -1 when no lucky integer exists")
37+
void findLucky_whenNoLuckyIntegerExists_shouldReturnMinusOne() {
38+
int[] arr = {1, 2, 2, 3, 3, 2, 1};
39+
assertEquals(-1, frequencyMap.findLucky(arr), "No number has a frequency equal to its value.");
40+
}
41+
42+
@Test
43+
@DisplayName("Should return -1 for an empty array")
44+
void findLucky_whenArrayIsEmpty_shouldReturnMinusOne() {
45+
int[] arr = {};
46+
assertEquals(-1, frequencyMap.findLucky(arr), "An empty array has no lucky integers.");
47+
}
48+
49+
@Test
50+
@DisplayName("Should handle an array where all elements are the same and form a lucky number")
51+
void findLucky_whenAllElementsAreSameAndLucky_shouldReturnTheNumber() {
52+
int[] arr = {4, 4, 4, 4};
53+
assertEquals(4, frequencyMap.findLucky(arr), "4 appears 4 times, so it is lucky.");
54+
}
55+
56+
@Test
57+
@DisplayName("Should handle an array where all elements are the same but not lucky")
58+
void findLucky_whenAllElementsAreSameAndNotLucky_shouldReturnMinusOne() {
59+
int[] arr = {5, 5, 5};
60+
assertEquals(-1, frequencyMap.findLucky(arr), "5 appears 3 times, so it is not lucky.");
61+
}
62+
63+
@Test
64+
@DisplayName("Should handle a single element array that is lucky")
65+
void findLucky_whenSingleElementIsLucky_shouldReturnTheNumber() {
66+
int[] arr = {1};
67+
assertEquals(1, frequencyMap.findLucky(arr), "1 appears 1 time, so it is lucky.");
68+
}
69+
70+
@Test
71+
@DisplayName("Should handle a single element array that is not lucky")
72+
void findLucky_whenSingleElementIsNotLucky_shouldReturnMinusOne() {
73+
int[] arr = {2};
74+
assertEquals(-1, frequencyMap.findLucky(arr), "2 appears 1 time, so it is not lucky.");
75+
}
76+
77+
@Test
78+
@DisplayName("Should handle a complex case with various numbers")
79+
void findLucky_withComplexArray_shouldReturnCorrectLargestLucky() {
80+
int[] arr = {7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 2, 2, 8, 9};
81+
assertEquals(7, frequencyMap.findLucky(arr), "Both 5 and 7 are lucky, but 7 is the largest.");
82+
}
83+
84+
@Test
85+
@DisplayName("Should ignore a smaller lucky number after a larger one is found")
86+
void findLucky_shouldNotBeReplacedBySmallerLuckyNumber() {
87+
// This test explicitly verifies the `num > lucky` part of the condition.
88+
// The map will contain two lucky numbers: 4 (appears 4 times) and 2 (appears 2 times).
89+
// The logic must correctly identify 4 as the largest lucky number,
90+
// even if it processes 2 after 4.
91+
int[] arr = {4, 4, 4, 4, 2, 2};
92+
assertEquals(4, frequencyMap.findLucky(arr), "The result should be the largest lucky number (4), not the smaller one (2).");
93+
}
94+
95+
@Test
96+
@DisplayName("Should correctly identify the largest lucky number when a smaller one is also present")
97+
void findLucky_shouldHandleMultipleLuckyNumbers() {
98+
// This test ensures that if a smaller lucky number (e.g., 2) is processed
99+
// after a larger one (e.g., 3), the larger one is correctly retained.
100+
// This specifically covers the case where `num == count` is true,
101+
// but `num > lucky` is false.
102+
int[] arr = {2, 2, 3, 3, 3};
103+
assertEquals(3, frequencyMap.findLucky(arr), "The largest lucky number should be 3, not 2.");
104+
}
105+
}

0 commit comments

Comments
 (0)