Two Pointers - Word Abbreviation
Estimated Time: 2 hours
Tech Stack: Java
Keywords: Data Structure - Algorithms
Experience Level: Beginner - Advanced
Category: TwoPointers
Skill: Parsing Numbers; Using Two Pointers on two different strings.
408. Valid Word Abbreviation
A string can be abbreviated by replacing any number of non-adjacent, non-empty substrings with their lengths. The lengths should not have leading zeros. For example, a string such as "substitution" could be abbreviated as (but not limited to):
-
"s10n" ("s ubstitutio n")
-
"sub4u4" ("sub stit u tion")
-
"12" ("substitution")
-
"su3i1u2on" ("su bst i t u ti on")
-
"substitution" (no substrings replaced)
-
The following are not valid abbreviations:
-
"s55n" ("s ubsti tutio n", the replaced substrings are adjacent)
-
"s010n" (has leading zeros)
-
"s0ubstitution" (replaces an empty substring)
Given a string word
and an abbreviation abbr
, return whether the string matches the given abbreviation.
A substring is a contiguous non-empty sequence of characters within a string.
Example 1:
Input: word = "internationalization", abbr = "i12iz4n" Output: true Explanation: The word "internationalization" can be abbreviated as "i12iz4n" ("i nternational iz atio n").
Example 2:
Input: word = "apple", abbr = "a2e" Output: false Explanation: The word "apple" cannot be abbreviated as "a2e".
Constraints:
1 <= word.length <= 20 word consists of only lowercase English letters. 1 <= abbr.length <= 10 abbr consists of lowercase English letters and digits. All the integers in abbr will fit in a 32-bit integer.
Solution:
package TwoPointers;
public class dAbbreviationValidator {
public static boolean validWordAbbreviation(String word, String abbr) {
int i = 0; // pointer for word
int j = 0; // pointer for abbr
while (i < word.length() && j < abbr.length()) {
char current = abbr.charAt(j);
// ๐ Case 1: Digit in abbreviation
if (Character.isDigit(current)) {
if (current == '0') {
return false; // ๐ซ Leading zero
}
int num = 0;
while (j < abbr.length() && Character.isDigit(abbr.charAt(j))) {
num = num * 10 + (abbr.charAt(j) - '0');
j++;
}
i += num; // Skip characters in word
}
// ๐ข Case 2: Letter in abbreviation
else {
if (i >= word.length() || word.charAt(i) != current) {
return false; // ๐ซ Mismatch
}
i++;
j++;
}
}
// โ
Both pointers must reach the end
return i == word.length() && j == abbr.length();
}
public static void main(String[] args) {
System.out.println(validWordAbbreviation("internationalization", "i12iz4n")); // true
System.out.println(validWordAbbreviation("apple", "a2e")); // false
System.out.println(validWordAbbreviation("substitution", "s10n")); // true
System.out.println(validWordAbbreviation("substitution", "s010n")); // false (leading zero)
System.out.println(validWordAbbreviation("substitution", "s0ubstitution")); // false (empty substring)
}
}
๐ Class Header
package AdHoc;
๐ฃ๏ธ Say it out loud:
โThis class is part of the
TwoPointers
package.โ
๐ Explanation:
Organizes your code inside a named package โ like putting a file in a folder.
public class AbbreviationValidator {
๐ฃ๏ธ Say it out loud:
โThis is a public class named
dAbbreviationValidator
.โ
๐ Explanation:
Defines the class where your logic and main
method will live.
๐ง Method Declaration
public static boolean validWordAbbreviation(String word, String abbr) {
๐ฃ๏ธ Say it out loud:
โDefine a public static method called
validWordAbbreviation
that takes a word and an abbreviation, and returns true or false.โ
๐ Explanation:
This method checks if abbr
is a valid abbreviation for word
.
๐งฎ Pointers Initialization
int i = 0; // pointer for word
int j = 0; // pointer for abbr
๐ฃ๏ธ Say it out loud:
โCreate two integer pointers
i
andj
, both starting at zero.โ
๐ Explanation:
i
tracks position in word
, j
tracks position in abbr
.
๐ Loop Through Characters
while (i < word.length() && j < abbr.length()) {
๐ฃ๏ธ Say it out loud:
โWhile both pointers are within bounds of their strings, keep looping.โ
๐ Explanation:
Loop continues as long as we havenโt finished parsing both strings.
๐ Get the Current Abbreviation Character
char current = abbr.charAt(j);
๐ฃ๏ธ Say it out loud:
โGet the current character in
abbr
at positionj
.โ
๐ Explanation:
Stores the character to decide if itโs a letter or digit.
๐ If the Current Character is a Digit
if (Character.isDigit(current)) {
๐ฃ๏ธ Say it out loud:
โIf the character is a digit...โ
๐ Explanation:
Abbreviations can include numbers that tell us how many characters to skip in the word.
๐ Check for Leading Zero
if (current == '0') {
return false;
}
๐ฃ๏ธ Say it out loud:
โIf the digit is zero, return false.โ
๐ Explanation:
Leading zeros like 01
, 007
are not valid โ skip is not allowed to begin with zero.
๐ข Parse the Number
int num = 0;
while (j < abbr.length() && Character.isDigit(abbr.charAt(j))) {
num = num * 10 + (abbr.charAt(j) - '0');
j++;
}
๐ฃ๏ธ Say it out loud:
โWhile weโre still seeing digits, build the full number and move
j
forward.โ
๐ Explanation:
This handles multi-digit numbers (e.g., "12"
), and moves the j
pointer past all digits.
๐งช Walkthrough 1: Parsing "15"
Let's say abbr = "a15b"
and we're starting at index j = 1
.
Step | abbr.charAt(j) | abbr.charAt(j) - '0' | num = num * 10 + digit | num value | j |
---|---|---|---|---|---|
1 | '1' | 1 | 0 * 10 + 1 | 1 | 2 |
2 | '5' | 5 | 1 * 10 + 5 | 15 | 3 |
3 | 'b' | โ not a digit | โ | end loop |
โ
Final result: num = 15
โฉ Skip Characters in Word
i += num;
๐ฃ๏ธ Say it out loud:
โMove the word pointer forward by that number.โ
๐ Explanation:
You're skipping over num
characters in the original word โ as instructed by the abbreviation.
๐ค If It's a Letter
} else {
if (i >= word.length() || word.charAt(i) != current) {
return false;
}
i++;
j++;
}
๐ฃ๏ธ Say it out loud:
โOtherwise, if itโs a letter, compare it with the current letter in
word
.โ
๐ Explanation:
If the letters donโt match, itโs invalid. If they do, move both pointers forward.
โ Final Check
return i == word.length() && j == abbr.length();
๐ฃ๏ธ Say it out loud:
โReturn true only if both pointers reached the end of their strings.โ
๐ Explanation:
Weโre only done if both strings are fully parsed โ no leftovers.
๐งช Test Code
public static void main(String[] args) {
๐ฃ๏ธ Say it out loud:
โMain method โ this is where the program starts.โ
๐ Explanation:
This is your test area to run the validator with different inputs.
System.out.println(validWordAbbreviation("internationalization", "i12iz4n")); // true
System.out.println(validWordAbbreviation("apple", "a2e")); // false
System.out.println(validWordAbbreviation("substitution", "s10n")); // true
System.out.println(validWordAbbreviation("substitution", "s010n")); // false
System.out.println(validWordAbbreviation("substitution", "s0ubstitution")); // false
๐ฃ๏ธ Say it out loud:
โCall the method with different test cases and print the results.โ
๐ Explanation:
Validates both correct and incorrect abbreviations to confirm your logic works as expected.
โ Output
true
false
true
false
false
โ๏ธ Challenges in the Word Abbreviation Problem
๐ง You're doing something that few learners take the time to do โ extracting wisdom from experience. Letโs now reflect on the challenges of the Word Abbreviation Validation problem.
๐ Challenge | ๐ฌ Why Itโs Tricky |
---|---|
1. Parsing numbers from a string | You have to manually parse digits into full numbers ("12" โ 12 ) without using Integer.parseInt() and handle them character by character. |
2. Dealing with leading zeros | A tricky constraint: abbreviations like "s010n" are invalid. You need to explicitly check for '0' and reject it early. |
3. Using two pointers on two different strings | Youโre walking two strings at the same time (word[i] and abbr[j] ), and syncing them correctly is harder than it looks, especially with skips involved. |
4. Skipping characters based on a parsed number | Once you parse a number from abbr , you skip that many characters in word . If you're not careful, youโll go out of bounds or mismatch letters. |
5. Comparing letters correctly | When not looking at a digit, you're expected to match the character in abbr with word . A mismatch at any position should immediately return false. |
6. Edge case handling (empty abbreviation, k = 0 , etc.) | Handling very short inputs, all-digit abbreviations (e.g., "10" ), or full word abbreviations requires precise thinking. |
7. Returning false on invalid structure | Not all abbreviation attempts are valid โ your algorithm needs to catch violations without false positives. |
8. Knowing when both pointers should end together | A valid abbreviation must consume the full word and abbr . If one finishes early, itโs invalid โ thatโs easy to forget. |
๐ง Bonus Challenge: Manual character-by-character parsing
Parsing a number from a string without built-in parsing teaches you how characters and digits relate via ASCII math, which is an advanced beginner skill you now have!
โ Summary
Concept | Challenge |
---|---|
Dual pointer logic | Advancing i and j correctly with different rules (digit vs letter) |
Number parsing | Interpreting multiple digits from abbreviation and handling edge cases |
Validation | Matching letters or rejecting early on invalid abbreviation structure |
Constraint handling | Rejecting abbreviations with leading zeros or invalid skips |
Final check | Making sure both i and j end together for a full match |
๐ก Reflection Insight
This problem builds precision, pointer mastery, and string parsing fluency โ a combo that makes you dangerous in string-heavy DSA challenges (like wildcard matching, regex parsing, or expression evaluation). You're building a Jedi toolkit, shinobi ๐ฅท๐๐ฅ