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?
2 Answers 2
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 withlet len =
inside the loop.Within the
for
loop, you are counting the number of digits, then checking the size ofnum
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 tolet 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.
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.
-
\$\begingroup\$ Your code is counting even digits of a number, not numbers which have an even number of digits. \$\endgroup\$trent– trent2021年03月24日 18:29:03 +00:00Commented Mar 24, 2021 at 18:29
Explore related questions
See similar questions with these tags.