How to generate a unique set of 3 digit numbers from an array

430 Views Asked by At

You are given an integer array digits, where each element is a digit. The array may contain duplicates.

You need to find all the unique integers that follow the given requirements:

The integer consists of the concatenation of three elements from digits in any arbitrary order. The integer does not have leading zeros. The integer is even. For example, if the given digits were [1, 2, 3], integers 132 and 312 follow the requirements.

Return a sorted array of the unique integers.

This is my attempt


        def findEvenNumbers(self, digits):
            list = set()
            finallist=[]
            for i in range(len(digits)):
                for j in range(i+1, len(digits)):
                    for k in range(j+1, len(digits)):
                        num1 = digits[i]
                        num2 = digits[j]
                        num3 = digits[k]
                        conct = str(num1) + str(num2) + str(num3)
                        if conct[0] != '0':
                            list.add(conct)
            for num in list:

                if int(num) %2 == 0:
                    finallist.append(int(num))
        
            finallist.sort()
            return finallist   `
**Input digits** = [2,1,3,0]
**Output** [130,210,230]
**Expected **[102,120,130,132,210,230,302,310,312,320]
**Input ** digits = [2,2,8,8,2]Output [222,228,282,288,882]Expected [222,228,282,288,822,828,882]
4

There are 4 best solutions below

2
juanpethes On

The issue is your code gets the combinations, not the permutations of the digits. This is because you start your inner loops with i+1 and j+1, so it doesn't go back to the start and get the other numbers. You can fix this by simply removing the i+1 and j+1 or use something like itertools.permutations for clearer code

from itertools import permutations

def find_even_numbers(digits):
    numbers = set()

    for digits in permutations(digits, r=3):
        number = int(''.join(map(str, digits)))
        if number % 2 == 0 and number >= 100:
            numbers.add(number)

    return sorted(list(numbers))
0
trincot On

As others already indicated, your loops should all iterate over all indices, just skipping the ones that have been selected by the more outer loops. So with the least change to your code, you'd have to change:

        for j in range(i+1, len(digits)):
            for k in range(j+1, len(digits)):

to:

        for j in range(len(digits)):  # start from 0
            if j == i:  # only exclude index i
                continue
            for k in range(len(digits)):  # start from 0
                if k in (i, j):  # only exclude indices i and j
                    continue

That will fix it. But here are some other remarks:

  • Try to eliminate bad numbers as soon as possible. For instance, it is the outermost loop that determines the leftmost digit, so there is no need to make the other loops when that digit happens to be zero; you can immediately proceed to the next iteration of the outer loop.

  • Don't use the name list for your list as list is the name of a native function

  • Avoid casting the digits to string and then back to integer again. You can use arithmetic to build the number without any strings involved

  • If acceptable to you, you could make use of enumerate as that gives you both the index and the digit at that index.

Here is your code with those adaptations:

def findEvenNumbers(digits):
    uniques = set()
    for i, hundreds in enumerate(digits):
        if hundreds:
            for j, tens in enumerate(digits):
                if i != j:
                    for k, ones in enumerate(digits):
                        if k not in (i, j) and k % 2 == 0:
                            uniques.add(hundreds * 100 + tens * 10 + ones)

    return sorted(uniques)
0
Zero On

Your code is only taking 1 of the permutations, whereas, there can be 6 permutations with 3 digits.

def findEvenNumbers(digits):
    final_list=[]
    for i in range(len(digits)):
        for j in range(i+1, len(digits)):
            for k in range(j+1, len(digits)):
                # possible permutations 'ijk, ikj, jik, jki, kij, kji'
                numbers = [
                    int(f'{digits[i]}{digits[j]}{digits[k]}'),
                    int(f'{digits[i]}{digits[k]}{digits[j]}'),
                    int(f'{digits[j]}{digits[i]}{digits[k]}'),
                    int(f'{digits[j]}{digits[k]}{digits[i]}'),
                    int(f'{digits[k]}{digits[i]}{digits[j]}'),
                    int(f'{digits[k]}{digits[j]}{digits[i]}'),
                ]

                numbers = [number for number in numbers if (number > 100) and (number%2==0)]
                final_list.extend(numbers)
    
    return sorted(set(final_list))

print(findEvenNumbers([2,1,3,0]))

Outputs:

[102, 120, 130, 132, 210, 230, 302, 310, 312, 320]
0
Alain T. On

you can work from 3 sets of digits:

  • First: All except zero
  • Middle: All
  • Last: Only even digits

With nested loops select the 3 digits using each of these sets.

When a digit is reused (same as first and/or second), check if you have enough of that digit in the input list to allow for the repetition.

By ordering the 3 sets of digits, the nested for loops will alway produce increasing 3-digit numbers.

def evenNums(digits):
    first  = sorted(set(digits)-{0})
    middle = sorted(set(digits))
    last   = sorted(set(digits)-{1,3,5,7,9})
    result = []
    for d0 in first:
        for d1 in middle:
            if d0==d1 and digits.count(d1)<2:
                continue
            for d2 in last:
                if digits.count(d2)<(d0==d2)+(d1==d2)+1:
                    continue
                result.append(d0*100+d1*10+d2)
    return result

print(evenNums([2,1,3,0]))
[102,120,130,132,210,230,302,310,312,320] 

Given that this is a small scale problem, you could use a really basic brute force approach that goes through all even numbers from 100 to 998 filtering on the ones that can be made with the input digits:

def evenNums(digits):
    return [ n for n  in range(100,999,2)
               for nd in [(n//100,n//10%10,n%10)]
               if all(nd.count(d)<=digits.count(d) for d in nd) ]