Problems - Set 1
Easy
Word Match
Design a method to find the frequency of occurrences of any given word in a book.
Approach 1: Using string split (One time)
package algo;
public class Problem1 {
public static void main(String[] args) {
String bookText = "Java is great. Java is powerful. Java is everywhere!";
String word = "Java";
int freq = getWordFrequency(bookText, word); // Output: 3
System.out.println(freq);
}
public static int getWordFrequency(String bookText, String word) {
if (bookText == null || word == null || word.isEmpty()) {
return 0;
}
String[] words = bookText.toLowerCase().split("\\W+"); // split on non-word characters
int count = 0;
for (String w : words) {
if (w.equals(word.toLowerCase())) {
count++;
}
}
return count;
}
}
Approach 2: Using StringUtils method
package algo;
import org.apache.commons.lang3.StringUtils;
public class Problem1 {
public static void main(String[] args) {
String bookText = "Java is great. Java is powerful. Java is everywhere!";
String word = "java";
System.out.println(StringUtils.countMatches(bookText.toLowerCase(), word.toLowerCase()));
}
}
Approach 3: Optimized for Multiple Calls
Preprocess the book text once into a frequency map. Then lookups are fast.
package algo;
import java.util.HashMap;
import java.util.Map;
public class WordFrequencyAnalyser {
private final Map<String, Integer> wordFrequencyMap;
public WordFrequencyAnalyser(String bookText) {
wordFrequencyMap = new HashMap<>();
preprocess(bookText);
}
private void preprocess(String bookText) {
if (bookText == null) {
return;
}
String[] words = bookText.toLowerCase().split("\\W+"); // non-word character split
for (String word : words) {
if (!word.isEmpty()) {
wordFrequencyMap.put(word, wordFrequencyMap.getOrDefault(word, 0) + 1);
}
}
}
public int getFrequency(String word) {
if (word == null || word.isEmpty()) {
return 0;
}
return wordFrequencyMap.getOrDefault(word.toLowerCase(), 0);
}
}
package algo;
public class Problem1 {
public static void main(String[] args) {
String bookText = "Java is great. Java is powerful. Java is everywhere!";
WordFrequencyAnalyser analyzer = new WordFrequencyAnalyser(bookText);
System.out.println(analyzer.getFrequency("java")); // Output: 3
System.out.println(analyzer.getFrequency("is")); // Output: 3
System.out.println(analyzer.getFrequency("powerful")); // Output: 1
System.out.println(analyzer.getFrequency("python")); // Output: 0
}
}
Medium
Pattern Matching
We are given:
A pattern string, e.g.,
"aabab"
A value string, e.g.,
"catcatgocatgo"
We need to return true if we can map each unique character (a
or b
) in the pattern to a non-empty substring in the value so that replacing the pattern with its mapped substrings gives the original value.
Example
Pattern:
"aabab"
Value:
"catcatgocatgo"
Let’s say
'a' = "cat"
'b' = "go"
Substituting:
Pattern → "a a b a b"
→ "cat cat go cat go"
→ matches value → return true
.
Constraints
Each
a
andb
must map to one consistent substring throughout the pattern.a
andb
must be different (but may be of any length).We can’t have
a = ""
orb = ""
(empty string is not allowed).
Approach
Count how many times
a
andb
appear in the pattern.Try all possible lengths of the substring assigned to
a
.For each possible length of
a
, calculate the length ofb
(from remaining length of value).Try assigning substrings to
a
andb
and check if the pattern reconstructs to the value.If we find a match, return
true
. Otherwise returnfalse
.
public class PatternMatcher {
public static boolean doesMatch(String pattern, String value) {
if (pattern.length() == 0) return value.length() == 0;
// Normalize pattern so that it starts with 'a'
char firstChar = pattern.charAt(0);
boolean isSwapped = false;
if (firstChar != 'a') {
pattern = swapPattern(pattern);
isSwapped = true;
}
int countA = countOf(pattern, 'a');
int countB = pattern.length() - countA;
int maxLenA = value.length() / Math.max(1, countA); // Avoid divide by zero
for (int lenA = 0; lenA <= maxLenA; lenA++) {
int remainingLength = value.length() - lenA * countA;
if (countB == 0) {
if (remainingLength != 0) continue;
if (isMatch(pattern, value, lenA, 0, isSwapped)) return true;
} else if (remainingLength % countB == 0) {
int lenB = remainingLength / countB;
if (isMatch(pattern, value, lenA, lenB, isSwapped)) return true;
}
}
return false;
}
private static boolean isMatch(String pattern, String value, int lenA, int lenB, boolean isSwapped) {
int index = 0;
String aStr = null;
String bStr = null;
for (char c : pattern.toCharArray()) {
int len = (c == 'a') ? lenA : lenB;
if (index + len > value.length()) return false;
String sub = value.substring(index, index + len);
if (c == 'a') {
if (aStr == null) aStr = sub;
else if (!aStr.equals(sub)) return false;
} else {
if (bStr == null) bStr = sub;
else if (!bStr.equals(sub)) return false;
}
index += len;
}
if (aStr != null && aStr.equals(bStr)) return false;
return true;
}
private static int countOf(String pattern, char c) {
int count = 0;
for (char ch : pattern.toCharArray()) {
if (ch == c) count++;
}
return count;
}
private static String swapPattern(String pattern) {
char[] swapped = new char[pattern.length()];
for (int i = 0; i < pattern.length(); i++) {
swapped[i] = pattern.charAt(i) == 'a' ? 'b' : 'a';
}
return new String(swapped);
}
public static void main(String[] args) {
System.out.println(doesMatch("aabab", "catcatgocatgo")); // true
System.out.println(doesMatch("aaaa", "catcatcatcat")); // true
System.out.println(doesMatch("abab", "redblueredblue")); // true
System.out.println(doesMatch("aabb", "xyzabcxzyabc")); // false
}
}
Arithmetic Evaluation
Given an arithmetic equation consisting of positive integers, +, -, * and / and no parentheses. Compute the result.
To evaluate an arithmetic expression like 2*3+5/6*3+15
(with no parentheses, only +
, -
, *
, and /
, and all positive integers), we must obey the order of operations:
Operator Precedence (BODMAS):
*
and/
(left to right)+
and-
(left to right)
public class ArithmeticEvaluator {
public static double evaluate(String expression) {
// Store numbers and the last operator
double currentNumber = 0;
char operation = '+'; // Assume '+' before first number
double result = 0;
double lastTerm = 0; // For handling * and / first
int n = expression.length();
for (int i = 0; i < n; i++) {
char ch = expression.charAt(i);
// If digit or decimal, build the number
if (Character.isDigit(ch) || ch == '.') {
int start = i;
while (i < n && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
i++;
}
currentNumber = Double.parseDouble(expression.substring(start, i));
i--; // adjust i because it will be incremented in the for-loop
}
// If current character is operator or we are at the end of the expression
if (!Character.isDigit(ch) && ch != ' ' && ch != '.' || i == n - 1) {
switch (operation) {
case '+':
result += lastTerm;
lastTerm = currentNumber;
break;
case '-':
result += lastTerm;
lastTerm = -currentNumber;
break;
case '*':
lastTerm = lastTerm * currentNumber;
break;
case '/':
lastTerm = lastTerm / currentNumber;
break;
}
operation = ch; // update the current operation
}
}
// Add the last processed term
result += lastTerm;
return result;
}
public static void main(String[] args) {
String expr = "2*3+5/6*3+15";
System.out.println("Result: " + evaluate(expr)); // Output: 23.5
}
}
Initialize:
result = 0
lastTerm = 0
operation = '+'
Read
2
Operation is
'+'
, solastTerm = 2
* 3
:Operation is
*
, solastTerm = 2 * 3 = 6
+ 5
:Add
lastTerm (6)
toresult
:result = 6
Set
lastTerm = 5
/ 6
:lastTerm = 5 / 6 ≈ 0.8333
* 3
:lastTerm = 0.8333 * 3 ≈ 2.5
+ 15
:Add
lastTerm (2.5)
toresult
:result = 6 + 2.5 = 8.5
Set
lastTerm = 15
End of string → Add
lastTerm (15)
to result → Final:8.5 + 15 = 23.5
This matches what BODMAS expects:
2 * 3 = 6
5 / 6 = 0.8333
0.8333 * 3 = 2.5
Final: 6 + 2.5 + 15 = 23.5
Last updated