Ambiguous Coordinates — Medium Problem & Solution
A 2-D point was written as "(x, y)", for example "(1, 3)" or "(2, 0.5)".
- Difficulty: Medium
- Topics: Strings, Backtracking, Enumeration
- Asked at: Amazon, Google
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
A 2-D point was written as "(x, y)", for example "(1, 3)" or "(2, 0.5)". Then every comma, decimal point and space was erased, leaving s — for example "(13)" or "(205)".
Return every point the original string could have been. A number in the original never had extraneous digits: no leading zeros ("00", "01", "001.5" are impossible), no trailing zeros after a decimal point ("1.0", "0.50" are impossible), and a decimal point always had at least one digit on each side (".5" is impossible, "0.5" is fine).
Write each point as "(x, y)" — exactly one space after the comma — and return the list sorted in ascending ASCII order.
Example 1
Input: s = "(123)"
Output: ["(1, 2.3)","(1, 23)","(1.2, 3)","(12, 3)"]
Example 2
Input: s = "(0010)"
Output: ["(0.01, 0)"]
Explanation: `"0, 010"` and `"00, 10"` have leading zeros; `"0.010"` has a trailing zero.
Example 3
Input: s = "(100)"
Output: ["(10, 0)"]
Constraints
4 <= s.length <= 12s[0] == '(' and s[s.length - 1] == ')'the other characters of s are digits
How to solve Ambiguous Coordinates
The two coordinates are independent once the comma position is fixed, so the answer is a union over comma positions of (legal spellings of the left) × (legal spellings of the right).
Approach
- Strip the parentheses to get the digit string
d. spell(x): includexifx == "0"orx[0] != '0'. For eachifrom 1 tolen(x) - 1, includex[:i] + "." + x[i:]when the integer partx[:i]is"0"or does not start with0, and the fractionx[i:]does not end with0.- For each comma position
i, add"(" + a + ", " + b + ")"for allainspell(d[:i])andbinspell(d[i:]). - Sort the strings by character code.
Why it works
A spelling is legal exactly when its integer part is canonical (no leading zero unless it is the single digit 0) and its fractional part, if present, is non-empty and does not end in 0 — the checks in spell. Every original point corresponds to one comma position and one spelling on each side, so the enumeration finds all of them once.
Complexity
- Time —
O(n^4) — n comma positions, O(n^2) spelling pairs, O(n) to build each - Space —
O(n^3) for the output
Pitfalls
"0"alone is legal, but"00","0.0"and"1.0"are not.- A part ending in
0can still be an integer ("10"), just never a decimal. - Keep the exact format
"(x, y)"with one space after the comma.
Reference solution
Python
from typing import List
def ambiguousCoordinates(s: str) -> List[str]:
d = s[1:-1]
def spell(x):
res = []
if x == '0' or x[0] != '0':
res.append(x)
for i in range(1, len(x)):
left, right = x[:i], x[i:]
if (left == '0' or left[0] != '0') and right[-1] != '0':
res.append(left + '.' + right)
return res
out = []
for i in range(1, len(d)):
for a in spell(d[:i]):
for b in spell(d[i:]):
out.append('(' + a + ', ' + b + ')')
out.sort()
return outJavaScript
var ambiguousCoordinates = function(s) {
var d = s.substring(1, s.length - 1);
var spell = function(x) {
var res = [];
if (x === '0' || x.charAt(0) !== '0') res.push(x);
for (var i = 1; i < x.length; i++) {
var left = x.substring(0, i), right = x.substring(i);
if ((left === '0' || left.charAt(0) !== '0') && right.charAt(right.length - 1) !== '0') {
res.push(left + '.' + right);
}
}
return res;
};
var out = [];
for (var i = 1; i < d.length; i++) {
var as = spell(d.substring(0, i));
var bs = spell(d.substring(i));
for (var a = 0; a < as.length; a++) {
for (var b = 0; b < bs.length; b++) out.push('(' + as[a] + ', ' + bs[b] + ')');
}
}
out.sort();
return out;
};Also on the editorial tab: C, C#, C++, Go, Java, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.
All 424 strings problems · the whole catalogue
Learn the technique: Strings · Backtracking