1694. Reformat Phone Number
Problem Description
In the given problem, we are tasked with reformatting a phone number provided to us as a string. The input number
may include digits, spaces ' '
, and/or dashes '-'
. Our objective is to reorganize the digits into a specific pattern and return the reformatted number. The following steps are a part of the reformatting process:
- First, we need to strip out all the spaces and dashes from the number.
- Then, we must group the digits into blocks containing 3 digits each, proceeding from left to right.
- We continue creating blocks of 3 digits until we're left with either 4, 3, or 2 digits.
- The remaining digits are then grouped based on the amount left.
- If there are 2 digits left, we keep them together as one block.
- If there are 3 digits, they also stay as a single block.
- If there are 4 digits, we split them into two blocks of 2 digits each.
- Finally, we join these blocks together with dashes to produce the final formatted number.
The challenge is to ensure that we never end up with a block of length 1 and that we have a maximum of two blocks of length 2.
Intuition
To solve this problem, we can divide the approach into several logical steps that can be programmatically implemented:
-
Cleaning the Input: We want our number string free from any non-numeric characters like spaces and dashes. We do this by applying the
replace
method to remove these characters. -
Creating Groups of Three: We then create as many groups of three as we can by iterating through the cleaned number. To facilitate this, we can use list comprehension, creating a sub-string for each group of three until we've handled all digits that can be grouped in threes.
-
Handling Remaining Digits: We always have to be careful about how we handle the last few digits of the phone number. Depending on whether there's a remainder of one or two after grouping digits by three, we handle the last blocks differently:
- If there is only one left over, we need to adjust the last block to only contain two of those digits, and combine the last digit with the penultimate pair, creating two blocks of two.
- If there are two left over, we simply add another block of two without needing any adjustments.
-
Joining the Blocks: After the blocks are correctly established, we can join them together into a single string with dashes in between using the
join
method.
By systematically applying these steps, we can ensure the phone number is reformatted as specified by the given rules.
Solution Approach
The solution iterates over the logic and patterns to reformat the phone number, as described under the intuition section. Here’s how the implementation aligns with that strategy:
-
Removing Non-numeric Characters: The first step is straightforward – remove any dashes and spaces from the input number, which is achieved with two
replace
function calls.number = number.replace("-", "").replace(" ", "")
-
Creating Groups of Three: Here we utilize Python's list comprehension combined with slicing. The comprehension iterates over a range
0
ton // 3
wheren
is the length of the cleaned number, and for each iterationi
, it slices a sub-string of the number starting fromi * 3
toi * 3 + 3
. Each slice is a block with up to 3 digits.ans = [number[i * 3 : i * 3 + 3] for i in range(n // 3)]
-
Handling Remaining Digits: Depending on the remainder when the cleaned number's length is divided by 3, we handle the final groups differently.
- If there's a remainder of 1 (
n % 3 == 1
), it suggests our last block inans
currently has 3 digits. We split this block to grab the first 2 digits, and then append another block with the last 2 digits, which include the last digit from the previous block and another digit from the end of the number string.if n % 3 == 1: ans[-1] = ans[-1][:2] ans.append(number[-2:])
- If the remainder is 2 (
n % 3 == 2
), we simply append one last block with the final two digits.elif n % 3 == 2: ans.append(number[-2:])
- If there's a remainder of 1 (
-
Joining the Blocks with Dashes: The final step is to join all the blocks with dashes to give us the formatted phone number. The
join
method is perfect for this purpose, turning our list of blocks into a single string.return "-".join(ans)
The described solution approach efficiently handles the process using simple built-in operations—a combination of string manipulations through replace
, slice
, and join
, along with list comprehension for constructing sub-strings—delivering an elegant and intuitive algorithm for the given task.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's take the following phone number string as an example: "123-45 6789
". We want to reformat it according to the rules in the problem description.
-
Removing Non-numeric Characters: First, we remove spaces and dashes.
Original: "123-45 6789" Cleaned: "123456789"
-
Creating Groups of Three: We then create blocks of three digits from the cleaned number:
Blocks of three: ["123", "456"] Remaining digits: "789"
-
Handling Remaining Digits: Since we have 3 remaining digits ("789"), we can add them as a single block:
Final blocks: ["123", "456", "789"]
-
Joining the Blocks with Dashes: Now, we combine the blocks with dashes to get the final phone number format:
Result: "123-456-789"
If we had a different number, say "123-45 678
", the process would differ in step 3, where we handle the remaining digits:
-
Removing Non-numeric Characters:
Original: "123-45 678" Cleaned: "12345678"
-
Creating Groups of Three:
Blocks of three: ["123", "456"] Remaining digits: "78"
-
Handling Remaining Digits: Since there are 2 remaining digits, they form the final block on their own:
Final blocks: ["123", "456", "78"]
-
Joining the Blocks with Dashes:
Result: "123-456-78"
In both cases, the solution approach systematically applies the reformatting rules to produce the correct phone number format.
Solution Implementation
1class Solution:
2 def reformatNumber(self, number: str) -> str:
3 # Remove dashes and spaces from the input string
4 cleaned_number = number.replace("-", "").replace(" ", "")
5
6 # Calculate the length of the cleaned number
7 length = len(cleaned_number)
8
9 # Break the cleaned number into chunks of three and store them in a list
10 chunks_of_three = [cleaned_number[i * 3: i * 3 + 3] for i in range(length // 3)]
11
12 # Depending on the remainder of the length divided by 3, process the end of the number
13 if length % 3 == 1:
14 # When there is one digit left after dividing into chunks of three,
15 # we need to break the last chunk into two digits and two digits
16 last_chunk = chunks_of_three[-1][:2] # Get first two digits of the last chunk
17 second_last_chunk = cleaned_number[-4:-2] # Get the two digits before the last chunk
18 chunks_of_three[-1] = second_last_chunk # Replace the last chunk with the two digits before it
19 chunks_of_three.append(last_chunk + cleaned_number[-2:]) # Add the final two pairs of two digits
20 elif length % 3 == 2:
21 # When there are two digits left after dividing into chunks of three,
22 # simply append them as the final chunk.
23 chunks_of_three.append(cleaned_number[-2:])
24
25 # Join the chunks with dashes and return the reformatted number
26 return "-".join(chunks_of_three)
27
1class Solution {
2 public String reformatNumber(String number) {
3 // Remove all dashes and spaces from the input number.
4 number = number.replace("-", "").replace(" ", "");
5
6 // Calculate the length of the cleaned number string.
7 int length = number.length();
8
9 // Use a list to store the parts of the reformatted number.
10 List<String> reformattedParts = new ArrayList<>();
11
12 // Divide the number into chunks of three and add them to the list.
13 for (int i = 0; i < length / 3; ++i) {
14 reformattedParts.add(number.substring(i * 3, i * 3 + 3));
15 }
16
17 // Handle the remaining digits after dividing by three.
18 int remainder = length % 3;
19 if (remainder == 1) {
20 // If there is exactly one digit left, take two from the last block and join with the last digit.
21 int lastBlockIndex = reformattedParts.size() - 1;
22 // Remove the last block and save the first two digits.
23 String lastBlockFirstPart = reformattedParts.remove(lastBlockIndex).substring(0, 2);
24 // Add the two digit part back to the list.
25 reformattedParts.add(lastBlockFirstPart);
26 // Add the final two digits as a separate block.
27 reformattedParts.add(number.substring(length - 2));
28 } else if (remainder == 2) {
29 // If there are two digits left, they form the final block on their own.
30 reformattedParts.add(number.substring(length - 2));
31 }
32
33 // Join all parts with dashes and return the reformatted number.
34 return String.join("-", reformattedParts);
35 }
36}
37
1class Solution {
2public:
3 string reformatNumber(string number) {
4 // Remove spaces and hyphens from the input number
5 string digitsOnly;
6 for (char digit : number) {
7 if (digit != ' ' && digit != '-') {
8 digitsOnly.push_back(digit);
9 }
10 }
11
12 // Determine the length of the new string with only digits
13 int length = digitsOnly.size();
14 vector<string> formattedParts;
15 // We divide the digits into blocks of 3
16 for (int i = 0; i < length / 3; ++i) {
17 formattedParts.push_back(digitsOnly.substr(i * 3, 3));
18 }
19
20 // Handle the remainder of the digits after division by 3
21 if (length % 3 == 1) {
22 // If there's one digit left after division by 3, we split the last block into two blocks of 2
23 // So we need to adjust the last block to have two digits
24 formattedParts.back() = formattedParts.back().substr(0, 2);
25 // Then, we take the last two digits and put them into a new block
26 formattedParts.push_back(digitsOnly.substr(length - 2));
27 } else if (length % 3 == 2) {
28 // If there are two digits left, simply add them as a block
29 formattedParts.push_back(digitsOnly.substr(length - 2));
30 }
31
32 // Combine the blocks into final formatted number with hyphens
33 string reformattedNumber;
34 for (auto& part : formattedParts) {
35 reformattedNumber += part;
36 reformattedNumber += "-";
37 }
38 // Remove the trailing hyphen
39 reformattedNumber.pop_back();
40
41 return reformattedNumber;
42 }
43};
44
1function reformatNumber(number: string): string {
2 // Filter out spaces and hyphens from the input string.
3 const cleanedNumbers = [...number].filter(c => c !== ' ' && c !== '-');
4 const totalDigits = cleanedNumbers.length;
5
6 // Transform the array of cleaned digits to a string formatted in blocks of digits, separated by hyphens.
7 return cleanedNumbers
8 .map((digit, index) => {
9 // Add a hyphen after every third digit except in specific conditions.
10 // Condition 1: When last block can be split into 2 blocks of 2 digits, add a hyphen before last 4 digits.
11 // Condition 2: Add a hyphen, if the current position is such that it's not the last or second last block.
12 if (
13 (index !== 0 && (index + 1) % 3 === 0 && index < totalDigits - 2) ||
14 (totalDigits % 3 === 1 && index === totalDigits - 4)
15 ) {
16 return digit + '-';
17 }
18 return digit;
19 })
20 .join(''); // Join the transformed array elements into a string.
21}
22
Time and Space Complexity
The time complexity of the code is O(n)
, where n
is the length of the input string. This complexity arises from the iteration and replacement methods called on the input string to remove spaces and hyphens, as well as the slicing to create the new format. Each of these operations has a linear complexity relative to the size of the input. The loop to construct the ans
list can iterate at most n/3
times, each iteration performing a constant amount of work, contributing to linear complexity as well.
The space complexity of the code is also O(n)
. This is because we create a new string that has approximately the same length as the input when we remove non-numeric characters. The ans
list itself will contain at most n/3 + 2
elements (in the case where the remaining length after slicing in threes is 1), which still contributes linearly to the space complexity due to the storage requirements of these substrings.
Learn more about how to find time and space complexity quickly using problem constraints.
Which of the following is a good use case for backtracking?
Recommended Readings
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!