Problems - Set 2
Easy
Circular Problem
Determine the position where the A-th item will be delivered in a circle of size B, starting from position C.
Understanding the Circle Behavior:
The positions are numbered from 1 to B, forming a circle.
After B, the numbering wraps around to 1.
Determine the Position:
Starting at position C, we deliver items sequentially.
The A-th item is delivered at the position calculated as:
Position=(C+A−1)%B
If the result of the modulo operation is 0, it means the position wraps around to B.
public static int findPosition(int A, int B, int C) {
// Calculate the position
int position = (C + A - 1) % B;
// If position is 0, it means we are at the last position in the circle
return position == 0 ? B : position;
}
Number Divisibility
Given a number represent in the form of an integer array A, where each element is a digit. We have to find whether there exists any permutation of the array A such that the number becomes divisible by 60. Return 1 if it exists, 0 otherwise.
Approach
Check for 0 (Divisibility by 5 and 2)
The number must contain at least one 0 because the last digit must be 0 for divisibility by 60.
Check for Divisibility by 3:
Compute the sum of the digits in A.
If the sum is divisible by 3, this condition is satisfied.
Check for an Additional Even Digit:
Besides the 0 required for divisibility by 5, ensure there is at least one more even digit (2,4,6,8) to satisfy divisibility by 2.
Check for edge case like all number 0
public static int isDivisibleBy60(int[] A) {
boolean hasZero = false; // To check if 0 is present
int sumOfDigits = 0; // Sum of all digits
int evenCount = 0; // Count of even digits (including 0)
int nonZeroCount = 0; // Count of non-zero digits
// Iterate through the array
for (int digit : A) {
if (digit == 0) {
hasZero = true; // Mark that 0 is found
} else {
nonZeroCount++; // Count non-zero digits
}
if (digit % 2 == 0) {
evenCount++; // Count even digits
}
sumOfDigits += digit; // Add the digit to the sum
}
// Special case: All zeros
if (nonZeroCount == 0) {
return 1; // A number like 0 or 00 is divisible by 60
}
// General case: Check all conditions for divisibility by 60
if (hasZero && sumOfDigits % 3 == 0 && evenCount > 1) {
return 1; // A permutation exists that is divisible by 60
}
return 0; // No valid permutation exists
}
Line Segment Intersection
Given two straight line segments (represented as a start point and an end point), compute the point of intersection, if any.
Basics
Each segment can be seen as part of an infinite line in 2D space.
We can represent each line in the general form:
Ax+By=C
For a line from (x1,y1) to (x2,y2), the general form is:
A=y2−y1
B=x1−x2
C=A⋅x1+B⋅y1,
For the two lines:
Line 1 (through P1,P2):
A1=y2−y1, B1=x1−x2, C1=A1x1+B1y1
Line 2 (through P3,P4):
A2=y4−y,,B2=x3−x4,C2=A2x3+B2y3
Solve the Linear System
Now solve:
A1x+B1y=C1 A2x+B2y=C2
Use Cramer's Rule or matrix inversion. The determinant is:
det=A1B2−A2B1
If det = 0
, the lines are parallel or coincident (no unique intersection).
Otherwise, the intersection point (x,y) is:
x=B2C1−B1C2/det
y=A1C2−A2C1/det
Check if the Point Lies on Both Segments
The above point lies on the infinite lines. You must ensure it lies within the bounds of both segments.
For a point r=(x,y) to lie on segment P=(x1,y1) to Q=(x2,y2), it must satisfy:
min(x1,x2) ≤ x ≤ max(x1,x2)
min(y1,y2) ≤ y ≤ max(y1,y2)
Repeat for both segments.
Solution
public class LineIntersection {
static class Point {
double x, y;
Point(double x, double y) { this.x = x; this.y = y; }
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
}
// Function to compute the intersection of two segments
public static Point getIntersection(Point p1, Point p2, Point p3, Point p4) {
double A1 = p2.y - p1.y;
double B1 = p1.x - p2.x;
double C1 = A1 * p1.x + B1 * p1.y;
double A2 = p4.y - p3.y;
double B2 = p3.x - p4.x;
double C2 = A2 * p3.x + B2 * p3.y;
double determinant = A1 * B2 - A2 * B1;
if (determinant == 0) {
// Lines are parallel or coincident
return null;
} else {
double x = (B2 * C1 - B1 * C2) / determinant;
double y = (A1 * C2 - A2 * C1) / determinant;
Point intersection = new Point(x, y);
if (isOnSegment(p1, p2, intersection) && isOnSegment(p3, p4, intersection)) {
return intersection;
} else {
return null; // Intersection point is outside the segments
}
}
}
private static boolean isOnSegment(Point p, Point q, Point r) {
return r.x >= Math.min(p.x, q.x) && r.x <= Math.max(p.x, q.x) &&
r.y >= Math.min(p.y, q.y) && r.y <= Math.max(p.y, q.y);
}
public static void main(String[] args) {
Point p1 = new Point(1, 1);
Point p2 = new Point(4, 4);
Point p3 = new Point(1, 4);
Point p4 = new Point(4, 1);
Point intersection = getIntersection(p1, p2, p3, p4);
System.out.println(intersection != null ? "Intersection at: " + intersection : "No intersection");
}
}
Tic Tac Toe
Design an algorithm to figure out if someone has won a game of tic-tac-toe.
Board is a 3x3 grid.
Each cell is either:
'X'
,'O'
, ornull
/''
(empty).Determine if
'X'
or'O'
has won.A win occurs when a player has 3 of their marks in:
A row
A column
A diagonal
public class TicTacToeWinner {
public static Character checkWinner(char[][] board) {
// Check rows
for (int i = 0; i < 3; i++) {
if (board[i][0] != '\0' &&
board[i][0] == board[i][1] &&
board[i][1] == board[i][2]) {
return board[i][0];
}
}
// Check columns
for (int j = 0; j < 3; j++) {
if (board[0][j] != '\0' &&
board[0][j] == board[1][j] &&
board[1][j] == board[2][j]) {
return board[0][j];
}
}
// Check diagonals
if (board[0][0] != '\0' &&
board[0][0] == board[1][1] &&
board[1][1] == board[2][2]) {
return board[0][0];
}
if (board[0][2] != '\0' &&
board[0][2] == board[1][1] &&
board[1][1] == board[2][0]) {
return board[0][2];
}
// No winner
return null;
}
public static void main(String[] args) {
char[][] board = {
{'X', 'O', 'X'},
{'O', 'X', 'O'},
{'O', 'X', 'X'}
};
Character winner = checkWinner(board);
System.out.println(winner != null ? "Winner: " + winner : "No winner");
}
}
Trailing zeros in n factorial
Write an algorithm which computes the number of trailing zeros in n factorial.
Trailing zeros are the zeros at the end of a number.
Example:
120
has 1 trailing zero
1000
has 3 trailing zeros
Trailing zeros are formed when the number is divisible by powers of 10.
What causes a 10 in factorial?
Every time we multiply numbers, a 10 is produced when we multiply 2 × 5
.
In a factorial like n! = 1 × 2 × 3 × ... × n
, there are many 2s and many 5s.
But 5s are less frequent than 2s, so:
The number of 10s = the number of times 5 appears in the prime factors of
n!
.
So the number of trailing zeros is equal to the number of times 5
appears as a factor in n!
.
How do we count how many 5s are there?
We look for:
Numbers divisible by 5: these give one 5
Numbers divisible by 25: these give two 5s
Numbers divisible by 125: these give three 5s, and so on.
So we add:
n / 5 + n / 25 + n / 125 + ...
We stop when the division result becomes zero.
Example: n = 100
100 / 5 = 20 → 20 numbers give at least one 5
100 / 25 = 4 → 4 of them give an extra 5
100 / 125 = 0 → done
So, total number of trailing zeros = 20 + 4 = 24

public class FactorialTrailingZeros {
public static int countTrailingZeros(int n) {
int count = 0;
for (int i = 5; n / i >= 1; i *= 5) {
count += n / i;
}
return count;
}
public static void main(String[] args) {
int n = 20;
int zeros = countTrailingZeros(n);
System.out.println("Trailing zeros in " + n + "! = " + zeros);
}
}
Smallest Difference
Given two arrays of integers, compute the pair of values (one value in each array) with the smallest (non-negative) difference. Return the difference.
Example
Input: a = {1, 3, 15, 11, 2}, b = {23, 127,235, 19, 8}
Output: 3. That is, the pair (11, 8).
Solution 1: Brute-force approach
package algo;
public class Problem1 {
public static void main(String[] args) {
int[] a = {1, 3, 15, 11, 2};
int[] b = {23, 127,235, 19, 8};
int a1 = 0, b1 = 0;
int diff = Integer.MAX_VALUE;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < b.length; j++) {
if (Math.abs(a[i] - b[j]) < diff) {
diff = Math.abs(a[i] - b[j]);
a1 = a[i];
b1 = b[j];
}
}
}
System.out.println("a = " + a1 + " b = " + b1 + " diff = " + diff);
}
}
Time Complexity: O(n × m)
This works by comparing every pair from array a
and b
using two nested loops.
Solution 2: Optimized Approach (Using Sorting + Two Pointers)
Sort both arrays:
a = [1, 2, 3, 11, 15] b = [8, 19, 23, 127, 235]
Use two pointers
i
andj
to walk througha
andb
:If
a[i] < b[j]
, try next value ina
(increasei
)If
a[i] > b[j]
, try next value inb
(increasej
)Always track the current absolute difference
Stop when we reach the end of either array.
import java.util.Arrays;
public class SmallestDifference {
public static int findSmallestDifference(int[] a, int[] b) {
Arrays.sort(a);
Arrays.sort(b);
int i = 0, j = 0;
int minDiff = Integer.MAX_VALUE;
int a1 = 0, b1 = 0;
while (i < a.length && j < b.length) {
int diff = Math.abs(a[i] - b[j]);
if (diff < minDiff) {
minDiff = diff;
a1 = a[i];
b1 = b[j];
}
// Move the pointer with the smaller value
if (a[i] < b[j]) {
i++;
} else {
j++;
}
}
System.out.println("a = " + a1 + ", b = " + b1 + ", diff = " + minDiff);
return minDiff;
}
public static void main(String[] args) {
int[] a = {1, 3, 15, 11, 2};
int[] b = {23, 127, 235, 19, 8};
findSmallestDifference(a, b);
}
}
Time Complexity
Sorting: O(n log n + m log m)
Linear scan: O(n + m)
Total: O(n log n + m log m)
Medium
Operations
Write methods to implement the multiply, subtract, and divide operations for integers. The results of all of these are integers. Use only the add operator
public static void main(String[] args) {
System.out.println("Subtract: " + subtract(10, 4)); // 6
System.out.println("Multiply: " + multiply(-3, 5)); // -15
System.out.println("Divide: " + divide(20, -4)); // -5
}
Subtract using only +
+
To subtract b
from a
, add the negative of b to a.
public static int negate(int x) {
int neg = 0;
int delta = x > 0 ? -1 : 1;
while (x != 0) {
x += delta;
neg += delta;
}
return neg;
}
public static int subtract(int a, int b) {
return a + negate(b);
}
Multiply using only +
+
Multiply a
and b
by adding a
repeatedly |b|
times.
public static int multiply(int a, int b) {
if (a == 0 || b == 0) return 0;
boolean negative = false;
if (b < 0) {
b = negate(b);
negative = !negative;
}
if (a < 0) {
a = negate(a);
negative = !negative;
}
int result = 0;
for (int i = 0; i < b; i++) {
result += a;
}
return negative ? negate(result) : result;
}
Divide using only +
+
Use repeated subtraction to see how many times b
fits into a
.
public static int divide(int a, int b) {
if (b == 0) throw new ArithmeticException("Division by zero");
boolean negative = false;
if (a < 0) {
a = negate(a);
negative = !negative;
}
if (b < 0) {
b = negate(b);
negative = !negative;
}
int quotient = 0;
int sum = 0;
while (sum + b <= a) {
sum += b;
quotient++;
}
return negative ? negate(quotient) : quotient;
}
Board Lengths
There are two types of planks, one of length shorter and one of length longer. We must use exactly K planks of wood. Write a method to generate all possible lengths for the board.
Solution 1: Brute Force (Two nested loops)
Loop through all combinations of shorter and longer planks that add up to k
.
public static Set<Integer> boardBruteForce(int shorter, int longer, int k) {
Set<Integer> result = new HashSet<>();
for (int i = 0; i <= k; i++) {
int numShorter = i;
int numLonger = k - i;
int totalLength = numShorter * shorter + numLonger * longer;
result.add(totalLength);
}
return result;
}
Time Complexity
O(k) because we loop from
0
tok
and compute a single value each time.
Solution 2: Optimized Approach (No Set, No Duplicates)
We avoid using a Set
and simply generate values in a loop if shorter != longer
.
public static List<Integer> boardOptimized(int shorter, int longer, int k) {
List<Integer> result = new ArrayList<>();
if (k == 0) return result;
if (shorter == longer) {
result.add(shorter * k); // Only one possible length
return result;
}
for (int i = 0; i <= k; i++) {
int totalLength = i * shorter + (k - i) * longer;
result.add(totalLength);
}
return result;
}
Time Complexity
O(k)
No duplicate check needed as each value is guaranteed unique if
shorter != longer
.
Sub Sort
Given an array, find the smallest subarray (from index m to n) such that if this part is sorted, the entire array becomes sorted. We aim to minimize n - m
.
Find where the array stops being sorted from left to right.
Find where the array stops being sorted from right to left.
Then:
Find min and max in the unsorted region.
Expand the left (
m
) to include any number greater thanmin
.Expand the right (
n
) to include any number less thanmax
.
Explanation
Given:
[1, 2, 4, 7, 10, 11, 7, 12, 6, 7, 16, 18, 19]
Find the first dip from the left where array is no longer sorted: Index
5
→11 > 7
Find the first rise from the right where array is no longer sorted: Index
8
→6 < 7
So the unsorted window is initially from 6
to 8
: [7, 12, 6]
→ But we now find the min = 6, max = 12
Expand
m
to include any number greater thanmin (6)
→ Expand left: 4th index is10
> 6 → 3rd index is7
> 6 → 2nd index is4
< 6 → stopSo
m = 3
Expand
n
to include any number less thanmax (12)
→ 9th is 7 < 12 → 10th is 16 > 12 → stopSo
n = 9
public static int[] findUnsortedSubarray(int[] arr) {
int n = arr.length;
// Step 1: find the initial left boundary
int left = 0;
while (left < n - 1 && arr[left] <= arr[left + 1]) {
left++;
}
if (left == n - 1) return new int[]{-1, -1}; // already sorted
// Step 2: find the initial right boundary
int right = n - 1;
while (right > 0 && arr[right] >= arr[right - 1]) {
right--;
}
// Step 3: find min and max in subarray [left, right]
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = left; i <= right; i++) {
min = Math.min(min, arr[i]);
max = Math.max(max, arr[i]);
}
// Step 4: expand left
while (left > 0 && arr[left - 1] > min) {
left--;
}
// Step 5: expand right
while (right < n - 1 && arr[right + 1] < max) {
right++;
}
return new int[]{left, right};
}
public static void main(String[] args) {
int[] arr = {1, 2, 4, 7, 10, 11, 7, 12, 6, 7, 16, 18, 19};
int[] result = findUnsortedSubarray(arr);
System.out.println("(" + result[0] + ", " + result[1] + ")");
// Output: (3, 9)
}
Difficult
Powerful Divisors
Given an integer array A of length N. For every integer X in the array, we have to find out the number of integers Y, such that 1 <= Y <= X, and the number of divisors of Y is a power of 2.
For example, 6 has the following divisors - [1, 2, 3, 6]. This is equal to 4, which is a power of 2. On the other hand, 9 has the following divisors [1, 3, 9] which is 3, which is not a power of 2. Return an array containing the answer for every X in the given array.
import java.util.ArrayList;
import java.util.List;
public class PowerfulDivisors {
public static List<Integer> powerfulDivisors(ArrayList<Integer> A) {
// Find the maximum number in the input array
int maxNumber = A.stream().max(Integer::compare).orElse(0);
// Precompute divisor counts for all numbers up to maxNumber
int[] divisorCounts = new int[maxNumber + 1];
for (int i = 1; i <= maxNumber; i++) {
for (int j = i; j <= maxNumber; j += i) {
divisorCounts[j]++;
}
}
// Precompute whether a divisor count is a power of 2
boolean[] isPowerful = new boolean[maxNumber + 1];
for (int i = 1; i <= maxNumber; i++) {
if (isPowerOfTwo(divisorCounts[i])) {
isPowerful[i] = true;
}
}
// Compute the number of "powerful divisors" for each number using cumulative approach
int[] powerfulDivisorCounts = new int[maxNumber + 1];
for (int i = 1; i <= maxNumber; i++) {
powerfulDivisorCounts[i] = powerfulDivisorCounts[i - 1] + (isPowerful[i] ? 1 : 0);
}
// Generate the result for the input array
List<Integer> result = new ArrayList<>();
for (int num : A) {
result.add(powerfulDivisorCounts[num]);
}
return result;
}
private static boolean isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
public static void main(String[] args) {
ArrayList<Integer> input = new ArrayList<>(List.of(10, 15, 20));
System.out.println(powerfulDivisors(input)); // Output: [8, 11, 15]
}
}
Last updated