Day 4 - Solving 5 String & Integer DSA Problems

Table of contents
- π Table of Contents
- π Introduction
- π§Ύ Approach:
- π§ What I Learned:
- Also this problem is important before we solve the String to Integer Problem
- π Approach:
- π¦ Physical Representation:
- π‘ Key Observations or Dry Run
- π§ What I Learned
- π οΈ Approach:
- π¦ Physical Representation
- π‘ Why idx = c - 'a'?
- π‘ Key Observations or Dry Run:
- π§ What I Learned:
- π§ Approach (Two-Pointer with Alphanumeric Filtering)
- π Step-by-Step Logic:
- π‘ Alphanumeric Helper Function:
- π Physical Representation (Step-by-step Dry Run)
- β Final Note:
- π§ What I Learned
- π Approach
- π¦ Physical Representation (Dry Run)
- π‘ Why We Did digit = s.charAt(i) - '0'?
- π§ What I Learned
- β Conclusion

π Table of Contents
Reverse Integer
First Unique Character in a String
Valid Anagram
Valid Palindrome
String to Integer
Conclusion
π Introduction
On Day 4 of my 90 Days DSA Challenge, I focused on strengthening my problem-solving skills with a mix of string-based and integer problems. These problems are essential for improving logical thinking and preparing for coding interviews. Iβve included clear explanations, code snippets, and dry run insights.
β Problem 1 β [Reverse Integer]
π§Ύ Approach:
To solve the Reverse Integer problem, we apply the classic number reversal method by extracting digits using modulus (%
) and constructing the reversed number. However, since weβre working with 32-bit signed integers, we must check for overflow before pushing digits into the result.
π Step-by-step logic:
Extract the last digit using
temp = val % 10
.Before multiplying the result
ans
by 10 and addingtemp
, check for overflow conditions.If all checks pass, update the result:
ans = ans * 10 + temp
.Divide
val
by 10 to move to the next digit.
π Overflow Edge Cases:
We must return 0 if reversing causes the number to go out of the 32-bit integer range:
Case 1:
ans > Integer.MAX_VALUE / 10
β Multiplying by 10 will definitely overflow.
β if(ans > Integer.MAX_VALUE / 10) return 0;
Case 2:
ans == Integer.MAX_VALUE / 10 && temp > 7
β Final digit will exceed max limit (2147483647).
β if(ans == Integer.MAX_VALUE / 10 && temp > 7) return 0;
Case 3:
ans < Integer.MIN_VALUE / 10
β Multiplying by 10 will underflow.
β if(ans < Integer.MIN_VALUE / 10) return 0;
Case 4:
ans == Integer.MIN_VALUE / 10 && temp < -8
β Final digit will exceed min limit (β2147483648).
β if(ans == Integer.MIN_VALUE / 10 && temp < -8) return 0;
This careful handling ensures we donβt encounter any integer overflows during reversal.
class Solution {
public int reverse(int x) {
int val=x;
int ans=0;
while(val!=0){
int temp=val%10;
if(ans>Integer.MAX_VALUE/10){
return 0;
}
if(ans==Integer.MAX_VALUE/10 && temp>7){
return 0;
}
if(ans<Integer.MIN_VALUE/10){
return 0;
}
if(ans==Integer.MIN_VALUE/10 && temp<-8){
return 0;
}
ans=(ans*10)+temp;
val=val/10;
}
return ans;
}
}
π‘ Key Observations or Dry Run:
Letβs dry run the input x = 123
to understand how the reversal logic works.
π Initial Values:
val = 123
ans = 0
β Iteration 1:
temp = 123 % 10 = 3
No overflow check triggers.
ans = 0 * 10 + 3 = 3
val = 123 / 10 = 12
β Iteration 2:
temp = 12 % 10 = 2
No overflow check triggers.
ans = 3 * 10 + 2 = 32
val = 12 / 10 = 1
β Iteration 3:
temp = 1 % 10 = 1
No overflow check triggers.
ans = 32 * 10 + 1 = 321
val = 1 / 10 = 0
β Final Output:
val = 0
, loop ends.Return
ans = 321
βοΈ Works as expected β the number has been reversed correctly.
π§ What I Learned:
I learned how to reverse an integer while handling edge cases related to 32-bit signed integer overflow, and how crucial it is to check boundary conditions before performing operations.
Also this problem is important before we solve the String to Integer Problem
β Problem 2 β [First Unique Character in a String]
π Approach:
Goal:
We are asked to find the index of the first non-repeating (unique) character in a given string. If no such character exists, return -1.Step 1 β Frequency Counting:
We use a
HashMap<Character, Integer>
to count how many times each character appears in the string.Loop through the string using a for-each loop and update the frequency using
map.put(c, map.getOrDefault(c, 0) + 1)
.
Step 2 β Identifying the Unique Character:
Now that we know the frequency of every character, we loop through the string again.
For each character, we check
if(map.get(char) == 1)
.If true, we return the current index, since this is the first unique character.
Step 3 β No Unique Character:
- If the loop completes and no character with frequency
1
is found, return-1
.
- If the loop completes and no character with frequency
class Solution {
public int firstUniqChar(String s) {
Map<Character,Integer>map=new HashMap<>();
for(char c : s.toCharArray()) {
map.put(c,map.getOrDefault(c,0)+1);
}
for(int i=0;i<s.length();i++){
if(map.get(s.charAt(i))==1){
return i;
}
}
return -1;
}
}
π¦ Physical Representation:
Letβs assume the input string is:
String s = "leetcode";
π s.toCharArray()
:
This converts the string into a character array like this:
Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Char | l | e | e | t | c | o | d | e |
So, s.toCharArray()
gives us:
['l', 'e', 'e', 't', 'c', 'o', 'd', 'e']
And now you can loop through it using a for-each loop:
for(char c : s.toCharArray()) {
// access each character like: c = 'l', then 'e', ...
}
π― s.charAt(i)
:
This accesses each character directly by index.
Example:
s.charAt(0) = 'l'
s.charAt(1) = 'e'
s.charAt(2) = 'e'
s.charAt(3) = 't'
...
Used in a loop:
for(int i = 0; i < s.length(); i++) {
char ch = s.charAt(i); // Picks each character by its index
}
π‘ Key Observations or Dry Run
Let's take the example input:
String s = "leetcode";
Convert to Character Array:
s.toCharArray()
transforms"leetcode"
into:['l', 'e', 'e', 't', 'c', 'o', 'd', 'e']
Frequency Counting:
As we loop through each character, we build a frequency map:'l'
β count becomes 1'e'
β count becomes 1; next occurrence makes it 2't'
β count becomes 1'c'
β count becomes 1'o'
β count becomes 1'd'
β count becomes 1
Final Map:
{ l: 1, e: 3, t: 1, c: 1, o: 1, d: 1 }
Finding the First Unique Character:
Looping with
s.charAt(i)
:- At
i = 0
:s.charAt(0)
is'l'
and its count is 1 β first unique character found.
- At
The function returns index
0
.
Thus, for the input "leetcode"
, the first unique character is 'l'
at index 0
.
π§ What I Learned
Working on this problem reinforced the importance of hash-based counting for efficient lookups. I also learned how two distinct string access methods (toCharArray()
and charAt(i)
) can be effectively used in tandem to simplify problem-solving.
β Problem 3 β [Valid Anagram]
π οΈ Approach:
To determine whether two strings s
and t
are anagrams of each other, we use a frequency count array for lowercase English letters.
Initialize a frequency array of size 26 (because there are 26 letters from
'a'
to'z'
):int[] freq = new int[26];
Populate the frequency array using the first string
s
:
For each characterc
ins
, convert it to an index using:idx = c - 'a'; freq[idx]++;
π‘ Why
c - 'a'
?
Characters in Java are internally represented by ASCII values. Subtracting'a'
(ASCII 97) from any lowercase letter gives us a unique index between 0 and 25.- Example:
'a' - 'a'
= 0,'b' - 'a'
= 1, ...,'z' - 'a'
= 25.
This maps each letter to a specific array index.
- Example:
Adjust the frequency array using the second string
t
:
For each character int
, subtract from the corresponding index:idx = c - 'a'; freq[idx]--;
Final Validation:
After processing both strings, loop through thefreq
array.
If any value is not zero, it means the strings differ in character count β returnfalse
.
If all values are zero β returntrue
.
class Solution {
public boolean isAnagram(String s, String t) {
int []freq=new int[26];
for(char c: s.toCharArray()){
int idx=c-'a';
freq[idx]=freq[idx]+1;
}
for(char c: t.toCharArray()){
int idx=c-'a';
freq[idx]=freq[idx]-1;
}
for(int i=0;i<26;i++){
if(freq[i]!=0){
return false;
}
}
return true;
}
}
π¦ Physical Representation
Letβs take an example:
s = "anagram"
t = "nagaram"
Step 1: Frequency array after processing s
Index | Char | Frequency |
0 | a | 3 |
1 | b | 0 |
2 | c | 0 |
3 | d | 0 |
4 | e | 0 |
5 | f | 0 |
6 | g | 1 |
12 | m | 1 |
13 | n | 1 |
17 | r | 1 |
... | ... | 0 |
π Each character in s
increments its frequency at index c - 'a'
.
Step 2: After processing t
All frequencies become 0 if t
is a valid anagram.
π‘ Why idx = c - 'a'
?
This expression maps a lowercase character 'a'
to 'z'
into the range 0
to 25
:
'a' - 'a'
= 0'b' - 'a'
= 1...
'z' - 'a'
= 25
This is useful for indexing the freq
array directly without using a HashMap.
π‘ Key Observations or Dry Run:
Letβs dry run for:
s = "anagram"
t = "nagaram"
After both loops:
All character frequencies cancel out.
freq
array becomes all zeroes β β valid anagram.
π§ What I Learned:
Using a fixed-size array to count character frequencies is a simple and optimized way to solve anagram problems when inputs are limited to lowercase letters. This avoids extra space from a HashMap.
β Problem 4 β [Valid Palindrome]
π§ Approach (Two-Pointer with Alphanumeric Filtering)
We use the two-pointer technique to compare characters from both ends of the string. Here's a breakdown of the steps:
π Step-by-Step Logic:
Initialize two pointers:
i = 0
(start of the string)j = s.length() - 1
(end of the string)
Skip non-alphanumeric characters:
If the character at index
i
is not alphanumeric, movei
to the right.If the character at index
j
is not alphanumeric, movej
to the left.This is handled by the helper method
Alphanumeric(char c)
which returnstrue
if the character is a letter or digit.
Compare characters:
Convert both characters to lowercase using
Character.toLowerCase()
.If they donβt match, the string is not a palindrome β return
false
.If they match, continue checking by moving
i
forward andj
backward.
If all corresponding characters match, return
true
.
π‘ Alphanumeric Helper Function:
public boolean Alphanumeric(char c){
return (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9');
}
This function checks if the character is:
A lowercase or uppercase letter
A digit from 0β9
class Solution {
public boolean Alphanumeric(char c){
return (c>='a' && c<='z')||(c>='A' && c<='Z')||(c>='0'&&c<='9');
}
public boolean isPalindrome(String s) {
int i=0;
int j=s.length()-1;
while(i<j){
char c1=s.charAt(i);
char c2=s.charAt(j);
if(!Alphanumeric( c1)){
i=i+1;
continue;
}
if(!Alphanumeric( c2)){
j=j-1;
continue;
}
if(Character.toLowerCase(c1)!=Character.toLowerCase(c2)){
return false;
}
i=i+1;
j=j-1;
}
return true;
}
}
π Physical Representation (Step-by-step Dry Run)
Letβs take the input string:
Input: "A man, a plan, a canal: Panama"
Step 1: Memory View of the String
Index | Character |
0 | A |
1 | |
2 | m |
3 | a |
4 | n |
5 | , |
6 | |
7 | a |
8 | |
9 | p |
10 | l |
11 | a |
12 | n |
13 | , |
14 | |
15 | a |
16 | |
17 | c |
18 | a |
19 | n |
20 | a |
21 | l |
22 | : |
23 | |
24 | P |
25 | a |
26 | n |
27 | a |
28 | m |
29 | a |
Step 2: Two Pointer Movement (Skipping non-alphanumeric)
i = 0
,j = 29
s[i] = 'A'
,s[j] = 'a'
β β Equal (case-insensitive) β move inward
i = 1
,s[i] = ' '
β β skipi = 2
,s[i] = 'm'
,j = 28
,s[j] = 'm'
β βi = 3
,s[i] = 'a'
,j = 27
,s[j] = 'a'
β βi = 4
,s[i] = 'n'
,j = 26
,s[j] = 'n'
β βi = 5
,s[i] = ','
β β skipi = 6
,s[i] = ' '
, β skipi = 7
,s[i] = 'a'
,j = 25
,s[j] = 'a'
β βi = 8
,s[i] = ' '
, β skipi = 9
,s[i] = 'p'
,j = 24
,s[j] = 'P'
β ββ¦ and so on β¦
All characters match when skipping non-alphanumeric ones, so it returns true
.
β Final Note:
This physical walk-through demonstrates how weβre not removing characters from the string.
We simply ignore non-alphanumeric characters on-the-fly using the helper function.
π§ What I Learned
I learned how to use the two-pointer technique to check for palindromes efficiently, while also handling non-alphanumeric characters and case sensitivity β all without extra space.
Problem 5 β [String to Integer (atoi)]
Input: s = "42"
The underlined characters are what is read in and the caret is the current reader position.
Step 1: "42" (no characters read because there is no leading whitespace)
^
Step 2: "42" (no characters read because there is neither a '-' nor '+')
^
Step 3: "42" ("42" is read in)
^
Example 2:
Input: s = " -042"
Step 1: " -042" (leading whitespace is read and ignored)
^
Step 2: " -042" ('-' is read, so the result should be negative)
^
Step 3: " -042" ("042" is read in, leading zeros ignored in the result)
^
Example 3:
Input: s = "1337c0d3"
Step 1: "1337c0d3" (no characters read because there is no leading whitespace)
^
Step 2: "1337c0d3" (no characters read because there is neither a '-' nor '+')
^
Step 3: "1337c0d3" ("1337" is read in; reading stops because the next character is a non-digit)
^
Example 4:
Input: s = "0-1"
Step 1: "0-1" (no characters read because there is no leading whitespace)
^
Step 2: "0-1" (no characters read because there is neither a '-' nor '+')
^
Step 3: "0-1" ("0" is read in; reading stops because the next character is a non-digit)
^
Example 5:
Input: s = "words and 987"
Reading stops at the first non-digit character 'w'.
Constraints:
0 <= s.le
ngth <= 200
s
consists of English letters (lower-case and upper-case), digits (0-9
),' '
,'+'
,'-'
, and'.'
.
π Approach
We need to convert a string into a 32-bit signed integer (int
), following these specific rules (just like the atoi
function in C/C++):
Ignore leading whitespaces:
Use a loop to skip all spaces until we reach a non-space character.Check for sign:
If the next character is+
or-
, we store the sign accordingly (+1
or-1
).Convert digits:
Keep converting digits one-by-one usingnum = num * 10 + digit
.Edge case - Overflow Handling:
To avoid overflow while building the number, we:Check if
num > Integer.MAX_VALUE / 10
(i.e., multiplication itself will overflow)Or if
num == Integer.MAX_VALUE / 10
and the next digit is too big (>=7
for positive,>=8
for negative)In both cases, we return
Integer.MAX_VALUE
orInteger.MIN_VALUE
.
Return Final Answer:
Multiply the result with thesign
and return.
class Solution {
public boolean isDigit(char c){
return (c>='0' && c<='9');
}
public int myAtoi(String s) {
//remove whitespace
int i=0;
int sign=1;
int num=0;
while(i<s.length() && s.charAt(i)==' ') {
i=i+1;
}
//Signedness
if(i<s.length()){
if(s.charAt(i)=='-'){
sign=-1;
i=i+1;
}
else if(s.charAt(i)=='+'){
sign=1;
i=i+1;
}
}
//conversion
while(i<s.length() && isDigit(s.charAt(i))){
int digit=s.charAt(i)-'0';
//rounding
if(num==Integer.MAX_VALUE/10){
if(sign==1){
if(digit>=7){
return Integer.MAX_VALUE;
}
}
else if(sign==-1){
if(digit>=8){
return Integer.MIN_VALUE;
}
}
}
if(num>Integer.MAX_VALUE/10){
if(sign==1){
return Integer.MAX_VALUE;
}
else{
return Integer.MIN_VALUE;
}
}
num=num*10+digit;
i=i+1;
}
return sign*num;
}
}
π¦ Physical Representation (Dry Run)
Letβs dry run the input:
Input: " -91283472332"
After Skipping Spaces:
s = "-91283472332"
i = 3
,sign = -1
,num = 0
Conversion Steps:
Step | i | s[i] | digit | num before | Overflow? | num after |
1 | 1 | '9' | 9 | 0 | No | 9 |
2 | 2 | '1' | 1 | 9 | No | 91 |
3 | 3 | '2' | 2 | 91 | No | 912 |
4 | 4 | '8' | 8 | 912 | No | 9128 |
5 | 5 | '3' | 3 | 9128 | No | 91283 |
6 | 6 | '4' | 4 | 91283 | No | 912834 |
7 | 7 | '7' | 7 | 912834 | No | 9128347 |
8 | 8 | '2' | 2 | 9128347 | No | 91283472 |
9 | 9 | '3' | 3 | 91283472 | No | 912834723 |
10 | 10 | '3' | 3 | 912834723 | Yes (>=8 for negative) | Return: Integer.MIN_VALUE |
Final Output: -2147483648
π‘ Why We Did digit = s.charAt(i) - '0'
?
We subtract '0'
(ASCII value of 48) from any digit character to get its actual integer value.
Example:
'3' - '0' = 51 - 48 = 3
This trick converts characters like'7'
directly into their numeric form.
π§ What I Learned
I learned how to carefully handle edge cases like:
Skipping whitespaces
Managing signs
Checking for overflow before it happens This problem taught me the importance of validating every step in input parsing logic.
β Conclusion
Day 4 of my 90 Days DSA Challenge was all about mastering string manipulation problems. From reversing integers and identifying the first unique character, to validating anagrams, checking for palindromes, and converting strings to integers β each problem helped me think more deeply about edge cases, ASCII value tricks, and input parsing techniques.
These problems may seem simple at first glance, but they build the foundation for handling real-world input validation, data cleaning, and low-level logic design. With every line of code, Iβve become more confident in breaking down problems and thinking through them with a structured approach.
On to Day 5 with more energy and curiosity! π
Subscribe to my newsletter
Read articles from Saivaishnav Ambati directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
