Missing Digit
Intro
Then also see \(x = 1\).
Have seen this in a coding interview on Coderbyte. Also check the similar Find The Unknown Digit :: Codewars 4kyu.
The input expression has this form:
operandA operator operandB = result
Assume the spaces will always be there. And we can simplify like this:
a o b = r
Some examples:
3 + 2 = x //=> 5
5 - x = 3 //=> 2
x / 2 = 4 //=> 8
12x + 2 = 125 //=> 3
Thinking about the solution
-
When \(x\) is on \(r\), no matter the operation:
-
Apply the operation to \(a\) and \(b\) to find \(r\).
-
-
Else, when the operation is addition or multiplication:
-
Apply the inverse operation on \(r\) and the known operand. For example, for \(x + 2 = 5\), do \(5 - 2\) to find \(a = 3\), and for \(3 + x = 5\), do \(5 - 3\) to find \(b = 2\).
-
-
Else, when the operation is subtraction or division:
-
When the known operand is on \(a\):
-
Apply the operation on \(a\) and \(r\). For example, for \(8 / x = 4\), do \(8 / 4\) to find \(b = 2\).
-
-
Else, when the known operand is on \(b\):
-
Apply the inverse operation on \(r\) and \(b\). For example, for \(x - 2 = 3\), do \(3 + 2\) to find \(a = 5\).
-
-

JavaScript
Assume these helper functions are in scope:
function int(val) {
return Number.parseInt(val, 10);
}
function str(val) {
return String(val);
}
const add = (x, y) => x + y;
const sub = (x, y) => x - y;
const mult = (x, y) => x * y;
const div = (x, y) => x / y;
Solution 1
We’ll create four functions for the four operations, a lookup table which matches the operator with its function, and an inverse operations lookup table that knows about the inverse operations.
Let’s start with something like this, simply following the algorithm idea outlined above.
const opTbl = {
'+': add,
'-': sub,
'*': mult,
'/': div,
};
const invOpTbl = {
'+': '-',
'-': '+',
'*': '/',
'/': '*',
};
function misDig(expr) {
const [a, op, b, _, r] = expr.split(' ');
let num;
let idx;
if (r.includes('x')) {
num = opTbl[op](int(a), int(b));
idx = r.indexOf('x');
} else if (['+', '*'].includes(op)) {
if (a.includes('x')) { (1)
num = opTbl[invOpTbl[op]](int(r), int(b));
idx = a.indexOf('x');
} else {
num = opTbl[invOpTbl[op]](int(r), int(a));
idx = b.indexOf('x');
}
} else {
if (a.includes('x')) { (2)
num = opTbl[invOpTbl[op]](int(b), int(r));
idx = a.indexOf('x');
} else {
num = opTbl[op](int(a), int(r));
idx = b.indexOf('x');
}
}
return int(str(num)[idx]);
}
The order in which we handled the cases is significant.
For example, just by checking the fact that “x”
appears on r
(the resulting side of the expression), we know the following conditions can only possibly match the other situtations, e.g. when “x”
shows up on a
or b
.
1 | Note the callout 1… |
2 | …and 2. |
They have the same condition and same code inside the block, which means there is probably a more clever way to check those conditions to reduce the number of them. So, we can instead do something like this, which also works just as well:
function misDig(expr) {
const [a, op, b, _, r] = expr.split(' ');
let num;
let idx;
if (r.includes('x')) {
num = opTbl[op](int(a), int(b));
idx = r.indexOf('x');
} else if (b.includes('x') && ['-', '/'].includes(op)) {
num = opTbl[op](int(a), int(r));
idx = b.indexOf('x');
} else if (b.includes('x')) {
num = opTbl[invOpTbl[op]](int(r), int(a));
idx = b.indexOf('x');
} else {
num = opTbl[invOpTbl[op]](int(r), int(b));
idx = a.indexOf('x');
}
return int(str(num)[idx]);
}
The two identical conditions and code have now become the last else
.
The code for that case needs to show up only once with this new approach.