[https://leetcode.com/problems/path-crossinghttps://leetcode.com/problems/finding-3-digit-even-numbers
Intuition
My first thought was to use a sliding window to find all of the possible 3 digit groupings, then separately find each possible permutation of numbers within each grouping.
This flawed first thinking stemmed from one issue off the get-go: I did NOT read the problem thorougly enough and thus I thought each group of 3 numbers had to be next to each other (consecutive). However, I later realized you could group any 3 numbers regardless of proximity, which later gave rise to the ReduceDigits()
method which allows the solution to run somewhat performately.
Approach
- Reduce digits to a maximum of 3 of each digit (3 0's, 3 1's, etc.)
- Find all possible unique groupings of 3 digits from the pool
- Check for leading zero
- Check last digit is even
- Return all even numbers that have passed all criteria
Complexity
-
Time complexity: Essentially
O(n)
but it's a bit of a complicated calculation - note there is an aboslute maximum of n=30 (3*10) -
Space complexity: Also should be linear, so
O(n)
Code
class TupleComparer : IEqualityComparer<Tuple<int,int,int>> {
public bool Equals(Tuple<int,int,int> x, Tuple<int,int,int> y)
{
var x_ordered = new List<int>(){x.Item1, x.Item2, x.Item3};
x_ordered.Sort();
var y_ordered = new List<int>(){y.Item1, y.Item2, y.Item3};
y_ordered.Sort();
return x_ordered[0] == y_ordered[0] && x_ordered[1] == y_ordered[1] && x_ordered[2] == y_ordered[2];
}
public int GetHashCode(Tuple<int,int,int> source)
{
int hash = 0;
hash = hash ^ source.Item1.GetHashCode();
hash = hash ^ source.Item2.GetHashCode();
hash = hash ^ source.Item3.GetHashCode();
return hash;
}
}
public class Solution {
public void GetPermutations(Tuple<int,int,int> digits, ref HashSet<int> hashes)
{
if(digits.Item1 != 0)
{
if(digits.Item3 % 2 == 0)
hashes.Add(digits.Item1 * 100 + digits.Item2 * 10 + digits.Item3);
if(digits.Item2 % 2 == 0)
hashes.Add(digits.Item1 * 100 + digits.Item3 * 10 + digits.Item2);
}
if(digits.Item2 != 0)
{
if(digits.Item3 % 2 == 0)
hashes.Add(digits.Item2 * 100 + digits.Item1 * 10 + digits.Item3);
if(digits.Item1 % 2 == 0)
hashes.Add(digits.Item2 * 100 + digits.Item3 * 10 + digits.Item1);
}
if(digits.Item3 != 0)
{
if(digits.Item2 % 2 == 0)
hashes.Add(digits.Item3 * 100 + digits.Item1 * 10 + digits.Item2);
if(digits.Item1 % 2 == 0)
hashes.Add(digits.Item3 * 100 + digits.Item2 * 10 + digits.Item1);
}
}
public HashSet<Tuple<int,int,int>> GetGroups(int[] digits)
{
HashSet<Tuple<int,int,int>> hashes = new HashSet<Tuple<int,int,int>>(new TupleComparer());
for(int i=0; i<digits.Length; i++)
{
var item1 = digits[i];
for(int j=0; j<digits.Length; j++)
{
if(i==j)
continue;
var item2 = digits[j];
for(int k=0; k<digits.Length; k++)
{
if(i==k || j==k)
continue;
var item3 = digits[k];
Tuple<int,int,int> group = new Tuple<int,int,int>(item1, item2, item3);
hashes.Add(group);
}
}
}
return hashes;
}
int[] ReduceDigits(int[] digits)
{
List<int> new_digits = new List<int>();
for(int i=0; i<10; i++)
{
int count = digits.Count(d => d==i);
for(int j=0; j<count && j<=3; j++)
{
new_digits.Add(i);
}
}
return new_digits.ToArray();
}
public int[] FindEvenNumbers(int[] digits)
{
var new_digits = ReduceDigits(digits);
var groups = GetGroups(new_digits);
Console.WriteLine($"Found {groups.Count()} groups:");
foreach(var group in groups)
Console.WriteLine($"{group.Item1}{group.Item2}{group.Item3}");
HashSet<int> evenNums = new HashSet<int>();
foreach(var group in groups)
{
GetPermutations(group, ref evenNums);
}
var result = evenNums.ToList();
result.Sort();
return result.ToArray();
}
}