1
\$\begingroup\$

I solved this problem: given an array/vector of numbers, return how many of them contain an even number of digits.

Constraints:

1 <= nums.length <= 500
1 <= nums[i] <= 10^5

Please review the code:

impl Solution {
    pub fn find_numbers(nums: Vec<i32>) -> i32 {
        let mut count = 0;
        let mut len = 0;

        if nums.len() <= 500 {
            for num in nums {
                let digit: Vec<_> = num
                    .to_string()
                    .chars()
                    .map(|d| d.to_digit(10).unwrap())
                    .collect();

                len = digit.len();
                if num > 100000 {
                    panic!("Too much greater values are in vector");
                }
                if len % 2 == 0 {
                    count += 1;
                }
            }
        }
        count
    }
}

Are there better ways to apply the constraints and solve the problem?

\$\endgroup\$
0
3
\$\begingroup\$

A couple of points. Firstly about the code you have listed.

  • Are the constraints problems to be enforced or assumptions you can make while writing your solution? It's odd to artificially limit it.

  • len does not need to be defined outside the loop. It is overwritten on each loop so could be replaced with let len = inside the loop.

  • Within the for loop, you are counting the number of digits, then checking the size of num and panicking if it's too high. It's better in general to exit as soon as possible if something's wrong, so in this case check the size before the more expensive process of counting digits.

  • In your character counting you are converting to characters, then back to digits before counting. If you only care about how many of them there are, you can leave them as characters. This gives num.to_string().chars().collect();

  • Once you have an iterator, you can use count instead of collecting to a vec and then finding the length. This reduces it further to let len = num.to_string().chars().count()

  • The outer for loop can also be replaced with an iterator

    nums.iter()
            .map(|n| n.to_string().chars().count())
            .filter(|n| n % 2 == 0)
            .count();
    

    This then doesn't need the count variable either.

Secondly, you ask about other ways to solve the problem. Converting between numbers and strings is slow, and keeping things as numbers wherever possible is generally preferable. In this case, the number of digits in a number (in base 10) is log10 of that number rounded up to the next integer. The edge cases are the powers of 10 which need to be 'rounded' to the next number.

The difficulty in writing this in rust is that log10 is only available for floating point types but as your values are bound 1 <= n <= 100_000, you can assume that all values can be mapped exactly to an f32. Numbers being >1 means that you can safely find a log (log isn't defined for negative numbers).

This lets you rewrite your method as something like

impl Solution {
    pub fn find_numbers(nums: Vec<i32>) -> i32 {
        // iterate over the numbers
        nums.iter()
            // for each n, find log10(n), round down and +1
            // this is the number of digits
            .map(|n| (*n as f32).log10().floor() as i32 + 1)
            // discard numbers that don't have an even number of digits
            .filter(|n| n % 2 == 0)
            // count how many are left
            .count()
    }
}

There is no restriction here of the size or number of numbers. If that is required, an additional check can be made before the iter call.

\$\endgroup\$
0
\$\begingroup\$

There is no constraint; it's just a limit of each variable (inputs).

That was the first thing, now we need to go to each element of this array/vector to check if its digit-length is even or odd by << modular and division operator >>. If it has, we should increment counter; otherwise do nothing (just break). Just do it with each number/element in current array.

int num = 234, counter = 0;
while(n){
    int digit = n % 10 ; 
    if( digit %2 == 0 )counter++ ; 
    n /= 10 ; //here is a tricky part 
   } 

Hope you understand. If you have any confusion, just ask me to clarify it.

\$\endgroup\$
1
  • \$\begingroup\$ Your code is counting even digits of a number, not numbers which have an even number of digits. \$\endgroup\$ – trentcl Mar 24 at 18:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.