0% found this document useful (0 votes)
70 views49 pages

Yuvraj (22scse1012063)

A prefix sum array is a derived array where each element at index i represents the sum of all elements from index 0 to i in the original array, allowing for efficient range sum queries and solving various subarray problems. It can be constructed in O(n) time and is used in applications such as game development, analytics, and financial systems. The document also includes various algorithms and classes for tasks like finding equilibrium indices, maximum subarray sums, and generating permutations.

Uploaded by

kg8028769
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
70 views49 pages

Yuvraj (22scse1012063)

A prefix sum array is a derived array where each element at index i represents the sum of all elements from index 0 to i in the original array, allowing for efficient range sum queries and solving various subarray problems. It can be constructed in O(n) time and is used in applications such as game development, analytics, and financial systems. The document also includes various algorithms and classes for tasks like finding equilibrium indices, maximum subarray sums, and generating permutations.

Uploaded by

kg8028769
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 49

Q1. Explain the concept of a prefix sum array and its applications.

Provide examples to support


your answer.

A prefix sum array is a derived array in which each element at index i represents the sum of all
elements from index 0 to i in the original array. In other words, for a given array arr[], the prefix
sum array prefix[] is defined as:

prefix[i]=arr[0]+arr[1]+...+arr[i]prefix[i] = arr[0] + arr[1] + ... +


arr[i]prefix[i]=arr[0]+arr[1]+...+arr[i]

How to Construct a Prefix Sum Array

For an array arr[] of size n, the prefix sum array can be built in O(n) time as:

java int[] prefix = new int[n]; prefix[0] = arr[0]; for (int i = 1; i < n; i++) {

prefix[i] = prefix[i - 1] + arr[i];

Applications of Prefix Sum Array

1. Efficient Range Sum Queries

Instead of summing elements from l to r repeatedly (which takes O(n) time), you can do it in
O(1) using:

sum(l,r)=prefix[r]−prefix[l−1]\text{sum}(l, r) = prefix[r] - prefix[l - 1]sum(l,r)=prefix[r]−prefix[l−1]

(If l = 0, then sum = prefix[r])

2. Solving Subarray Problems Prefix sums help in finding:

• Maximum sum subarrays

• Number of subarrays with a certain sum

• Zero-sum subarrays

3. Frequency Count and Range Updates

In problems involving multiple range updates or queries (like adding a value x to all elements in
a range), a variant called difference array (inverse of prefix sum) is used.
4. 2D Prefix Sum (Matrix)

Used to efficiently calculate the sum of elements in a sub-matrix.

5. Real-World Use Cases

• Game development (tracking scores or health over time)

• Analytics platforms (aggregating data over a time window)

• Financial systems (calculating cumulative profit/loss)

Q2. Program to find sum of elements in range [L, R] using prefix sum array class

PrefixSum {

int[] prefix;

PrefixSum(int[] arr) { prefix =

new int[arr.length]; prefix[0] =

arr[0]; for (int i = 1; i <

arr.length; i++) { prefix[i] =

prefix[i - 1] + arr[i];

int rangeSum(int L, int R) {

if (L == 0) return prefix[R];

return prefix[R] - prefix[L - 1];

}
Algorithm:

1. Create a prefix array.

2. Fill prefix[i] = prefix[i-1] + arr[i].

3. For range [L, R], return prefix[R] - prefix[L-1].

Time: O(n) for preprocessing, O(1) per query

Space: O(n)

Q3. Find equilibrium index in array

class EquilibriumIndex { static int

findEquilibrium(int[] arr) { int

total = 0, leftSum = 0; for (int

num : arr) total += num; for (int i

= 0; i < arr.length; i++) { total -

= arr[i]; if (leftSum == total)

return i; leftSum += arr[i];

return -1;

Algorithm:

1. Find total sum.

2. Traverse and maintain left sum.

3. Check if left sum equals total sum - current element.


Time: O(n), Space: O(1)

Q4. Check if array can be split into two parts with equal prefix and suffix sums

class SplitEqualSum { static boolean canSplit(int[] arr) { int total = 0,

prefixSum = 0; for (int num : arr) total += num; for (int i = 0; i <

arr.length - 1; i++) { prefixSum += arr[i]; if (prefixSum == total -

prefixSum) return true;

return false;

Time: O(n), Space: O(1)

Q5. Maximum sum of subarray of size K class

MaxSubarraySumK {

static int maxSum(int[] arr, int k) { int

windowSum = 0, maxSum = 0; for (int i = 0; i

< k; i++) windowSum += arr[i]; maxSum =

windowSum;

for (int i = k; i < arr.length; i++) {

windowSum += arr[i] - arr[i - k]; maxSum =

Math.max(maxSum, windowSum);
}

return maxSum;

Sliding window used

Time: O(n), Space: O(1)

Q6. Length of the longest substring without repeating characters

class LongestUniqueSubstring { static int

lengthOfLongestSubstring(String s) { int[] lastIndex = new

int[256]; for (int i = 0; i < 256; i++) lastIndex[i] = -1; int

maxLength = 0, start = 0;

for (int end = 0; end < s.length(); end++) {

if (lastIndex[s.charAt(end)] >= start) {

start = lastIndex[s.charAt(end)] + 1;

lastIndex[s.charAt(end)] = end; maxLength =

Math.max(maxLength, end - start + 1);

return maxLength;

Algorithm:
1. Use a sliding window with a map to store last seen index.

2. Update window start when a repeating character is found.

Time: O(n), Space: O(1) [for fixed ASCII charset]

Example: "abcabcbb" -> 3

Q7. Explain the sliding window technique and its use in string problems

Sliding window is a technique where we maintain a subset (window) of the data and slide it
across the array/string.

Useful for problems requiring contiguous subarrays or substrings.

Examples:

- Longest substring without repeating characters

- Max sum of subarray of size K

- Anagram detection in string

Time Complexity: O(n), Space: O(1)/O(k)

Q8. Longest palindromic substring class

LongestPalindrome { static String

longestPalindrome(String s) { if (s.length()

< 1) return ""; int start = 0, end = 0;

for (int i = 0; i < s.length(); i++) { int len1

= expandFromMiddle(s, i, i); int len2 =

expandFromMiddle(s, i, i + 1); int len =

Math.max(len1, len2); if (len > end -


start) { start = i - (len - 1) / 2;

end = i + len / 2;

return s.substring(start, end + 1);

static int expandFromMiddle(String s, int left, int right) { while (left >=

0 && right < s.length() && s.charAt(left) == s.charAt(right)) {

left--;

right++;

return right - left - 1;

Algorithm: Expand Around Center

Time: O(n^2), Space: O(1)

Example: "babad" -> "bab" or "aba"

Q9. Longest common prefix among strings class

LongestCommonPrefix { static String

longestCommonPrefix(String[] strs) { if

(strs.length == 0) return ""; String prefix = strs[0];

for (int i = 1; i < strs.length; i++) { while


(strs[i].indexOf(prefix) != 0) { prefix =

prefix.substring(0, prefix.length() - 1); if

(prefix.isEmpty()) return "";

return prefix;

Algorithm:

1. Start with first string as prefix.

2. Trim prefix if next string doesn't start with it.

Time: O(n*m), Space: O(1)

Q10. Generate all permutations of a string

class StringPermutations { static void

permute(String str, int l, int r) {

if (l == r)

System.out.println(str);

else { for (int i = l; i <=

r; i++) { str =

swap(str, l, i);

permute(str, l + 1, r);

str = swap(str, l, i);

}
}

static String swap(String a, int i, int j) {

char[] charArray = a.toCharArray();

char temp = charArray[i];

charArray[i] = charArray[j];

charArray[j] = temp; return

String.valueOf(charArray);

Backtracking approach

Time: O(n*n!), Space: O(n)

Example: abc -> abc, acb, bac, bca, cab, cba

Q11. Find two numbers in a sorted array

that add up to a target class TwoSumSorted

{ static int[] twoSum(int[] nums, int target)

{ int left = 0, right = nums.length - 1;

while (left < right) { int sum = nums[left]

+ nums[right]; if (sum == target) return

new int[]{left, right}; if (sum < target)

left++; else right--;

return new int[]{-1, -1};

}
Two-pointer approach

Time: O(n), Space: O(1)

Q12. Lexicographically next greater permutation

class NextPermutation { static void

nextPermutation(int[] nums) { int i =

nums.length - 2; while (i >= 0 && nums[i] >=

nums[i + 1]) i--;

if (i >= 0) { int j =

nums.length - 1; while

(nums[j] <= nums[i]) j--;

swap(nums, i, j);

reverse(nums, i + 1);

static void swap(int[] nums, int i, int j) {

int temp = nums[i]; nums[i] =

nums[j]; nums[j] = temp;

static void reverse(int[] nums, int start) {

int end = nums.length - 1; while (start


< end) { swap(nums, start++, end--

);

Time: O(n), Space: O(1)

Q13. Merge two sorted linked lists

class MergeSortedLists { static

class ListNode {

int val;

ListNode next;

ListNode(int x) { val = x; }

static ListNode mergeTwoLists(ListNode l1, ListNode l2) {

ListNode dummy = new ListNode(-1), curr = dummy;

while (l1 != null && l2 != null) {

if (l1.val < l2.val) {

curr.next = l1; l1 = l1.next;


} else { curr.next =

l2; l2 = l2.next;

curr = curr.next;

curr.next = (l1 != null) ? l1 : l2;

return dummy.next;

Time: O(n + m), Space: O(1)

Q14. Median of two sorted arrays using binary search class MedianSortedArrays {

static double findMedianSortedArrays(int[] nums1, int[] nums2) { if (nums1.length

> nums2.length) return findMedianSortedArrays(nums2, nums1);

int x = nums1.length, y = nums2.length;

int low = 0, high = x;

while (low <= high) { int partitionX =

(low + high) / 2; int partitionY = (x + y + 1)

/ 2 - partitionX;

int maxX = (partitionX == 0) ? Integer.MIN_VALUE : nums1[partitionX - 1];

int minX = (partitionX == x) ? Integer.MAX_VALUE : nums1[partitionX];


int maxY = (partitionY == 0) ? Integer.MIN_VALUE : nums2[partitionY - 1];

int minY = (partitionY == y) ? Integer.MAX_VALUE : nums2[partitionY];

if (maxX <= minY && maxY <= minX) {

if ((x + y) % 2 == 0)

return ((double)Math.max(maxX, maxY) + Math.min(minX, minY)) / 2;

else

return (double)Math.max(maxX, maxY);

} else if (maxX > minY) {

high = partitionX - 1;

} else {

low = partitionX + 1;

throw new IllegalArgumentException();

Time: O(log(min(n, m))), Space: O(1)

Q15. Find the k-th smallest element in a sorted matrix

import java.util.PriorityQueue; class

KthSmallestInMatrix { static class Node implements

Comparable<Node> {

int val, r, c;

Node(int v, int r, int c) { this.val = v; this.r = r; this.c = c; }

public int compareTo(Node o) { return this.val - o.val; }


}

static int kthSmallest(int[][] matrix, int k) {

int n = matrix.length;

PriorityQueue<Node> pq = new PriorityQueue<>(); for

(int i = 0; i < n; i++) pq.offer(new Node(matrix[i][0], i, 0));

while (--k > 0) { Node node = pq.poll(); if (node.c < n - 1)

pq.offer(new Node(matrix[node.r][node.c + 1], node.r, node.c + 1));

return pq.peek().val;

Time: O(k log n), Space: O(n)

Q16. Find the majority element (appears more than n/2 times)

class MajorityElement { static int majorityElement(int[] nums)

{ int count = 0, candidate = -1; for (int num : nums) {

if (count == 0) { candidate = num; count = 1;

} else if (candidate == num) {

count++; } else {

count--;

}
return candidate;

Moore’s Voting Algorithm

Time: O(n), Space: O(1)

Q17. Trapping Rain Water

class TrappingRainWater {

static int trap(int[] height) { int left =

0, right = height.length - 1; int leftMax

= 0, rightMax = 0, result = 0; while (left

< right) { if (height[left] <

height[right]) { if (height[left] >=

leftMax) leftMax = height[left];

else result += leftMax -

height[left]; left++;

} else { if

(height[right] >= rightMax)

rightMax = height[right];

else result += rightMax -

height[right];

right--;

return result;

}
}

Two-pointer approach

Time: O(n), Space: O(1)

Q18. Maximum XOR of two numbers in an array

class MaximumXOR { static int

findMaximumXOR(int[] nums) { int max = 0,

mask = 0; Set<Integer> set = new

HashSet<>();

for (int i = 31; i >= 0; i--) {

mask |= (1 << i); set.clear();

for (int num : nums)

set.add(num & mask); int temp =

max | (1 << i); for (int prefix : set)

{ if (set.contains(prefix ^

temp)) { max = temp;

break;

return max;

Time: O(n), Space: O(n)


Q19. Maximum Product Subarray class MaxProductSubarray {

static int maxProduct(int[] nums) { int maxProd = nums[0],

minProd = nums[0], result = nums[0]; for (int i = 1; i <

nums.length; i++) { if (nums[i] < 0) { int temp =

maxProd; maxProd = minProd; minProd =

temp;

maxProd = Math.max(nums[i], maxProd * nums[i]);

minProd = Math.min(nums[i], minProd * nums[i]); result

= Math.max(result, maxProd);

return result;

Time: O(n), Space: O(1)

Q20. Count numbers with unique digits (for given number of digits)

class CountUniqueDigits { static int

countNumbersWithUniqueDigits(int n) {

if (n == 0) return 1; int res = 10,

uniqueDigits = 9, available = 9; while (n-- >

1 && available > 0) { uniqueDigits *=


available; res += uniqueDigits;

available--;

return res;

Time: O(n), Space: O(1)

Q21. Count number of 1s in binary representation from 0 to n

class CountBits { static int[] countBits(int n) { int[] res =

new int[n + 1]; for (int i = 1; i <= n; i++) { res[i] =

res[i >> 1] + (i & 1);

return res;

Time: O(n), Space: O(n)

Q22. Check if a number is power of two using bit manipulation

class PowerOfTwo { static boolean isPowerOfTwo(int n) {

return n > 0 && (n & (n - 1)) == 0;

}
}

Time: O(1), Space: O(1)

Q23. Maximum XOR of two numbers

class MaximumXOR { static int

findMaximumXOR(int[] nums) { int

max = 0, mask = 0;

Set<Integer> set = new HashSet<>();

for (int i = 31; i >= 0; i--) {

mask |= (1 << i); set.clear();

for (int num : nums)

set.add(num & mask); int temp =

max | (1 << i); for (int prefix : set)

{ if (set.contains(prefix ^

temp)) { max = temp;

break;

return max;

}
Time: O(n), Space: O(n)

Q24. Concept of Bit Manipulation

Bit Manipulation involves using bitwise operators (&, |, ^, ~, <<, >>) for optimizing algorithms.

Advantages:

- Faster computation

- Memory efficiency

- Useful in masks, toggling bits, and solving complex problems like subset generation.

Q25. Next greater element for each element in an array

class NextGreaterElement { static int[]

nextGreaterElements(int[] nums) { Stack<Integer>

stack = new Stack<>(); int[] res = new

int[nums.length]; Arrays.fill(res, -1); for (int i =

0; i < nums.length; i++) {

while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) {

res[stack.pop()] = nums[i];

stack.push(i);

return res;
}

Time: O(n), Space: O(n)

Q26. Remove the n-th node from end of a singly linked list class

RemoveNthNode {

static class ListNode {

int val;

ListNode next;

ListNode(int x) { val = x; }

static ListNode removeNthFromEnd(ListNode head, int n) {

ListNode dummy = new ListNode(0); dummy.next = head;

ListNode first = dummy, second = dummy;

for (int i = 0; i <= n; i++) first = first.next;

while (first != null) { first = first.next;

second = second.next;

second.next = second.next.next;

return dummy.next;

Time: O(n), Space: O(1)


Q27. Find the node where two singly linked lists intersect class

LinkedListIntersection {

static RemoveNthNode.ListNode getIntersectionNode(RemoveNthNode.ListNode headA,


RemoveNthNode.ListNode headB) {

RemoveNthNode.ListNode a = headA, b = headB;

while (a != b) { a = (a == null)

? headB : a.next; b = (b == null)

? headA : b.next;

return a;

Time: O(n), Space: O(1)

Q28. Implement two stacks in a single array

class TwoStacks { int size, top1, top2;

int[] arr;

TwoStacks(int n) {

size = n; arr

= new int[n];
top1 = -1; top2

= n;

void push1(int x) { if (top1 <

top2 - 1) arr[++top1] = x;

void push2(int x) { if (top1 <

top2 - 1) arr[--top2] = x;

int pop1() { if (top1 >= 0) return

arr[top1--]; return -1;

int pop2() {

if (top2 < size) return arr[top2++];

return -1;

Time: O(1), Space: O(n)


Q29. Check if integer is palindrome without converting to string

class PalindromeNumber { static boolean isPalindrome(int x) {

if (x < 0 || (x % 10 == 0 && x != 0)) return false; int reversed

= 0; while (x > reversed) { reversed = reversed * 10 + x

% 10;

x /= 10;

return x == reversed || x == reversed / 10;

Time: O(log n), Space: O(1)

Q30. Explain Linked Lists and Their Applications. Provide examples to support your answer.

A Linked List is a linear data structure in which elements, called nodes, are stored in separate
memory locations. Each node contains two parts:

1. Data – the value stored in the node.

2. Pointer (or link) – a reference to the next node in the sequence.

Unlike arrays, linked lists do not require contiguous memory allocation. This makes them
dynamic and flexible in memory usage.

Types of Linked Lists:

• Singly Linked List – each node points to the next node.

• Doubly Linked List – each node points to both next and previous nodes.

• Circular Linked List – last node points back to the first node.
Key Features

• Dynamic memory allocation – no need to declare size beforehand.

• Efficient insertion/deletion – especially at the beginning or middle.

• No memory wastage – grows or shrinks as needed.

Applications of Linked Lists

1. Dynamic Memory Allocation

Linked lists are ideal for allocating memory on-the-fly. For example, in operating systems, the
kernel uses linked lists to manage memory blocks.

2. Efficient Insertions and Deletions

In arrays, inserting or deleting elements requires shifting, which takes O(n) time. Linked lists
perform these operations in O(1) time if the pointer to the node is available.

3. Implementation of Data Structures

• Stacks – using a singly linked list where insertion and deletion happen at the head.

• Queues – with insertion at the tail and deletion from the head.

• Hash Tables – for handling collisions via chaining (linked lists).

• Graphs – adjacency list representation uses linked lists for storing neighboring vertices.

4. Polynomial Arithmetic

Linked lists can represent polynomials where each node holds the coefficient and exponent. This
is useful in symbolic algebra and compiler design.

5. Music or Image Viewer Applications

Doubly linked lists allow forward and backward navigation between songs/images.

6. Real-World Use Cases

• Undo functionality in text editors (implemented using stacks with linked lists).

• Browser history (back and forward functionality using doubly linked lists).

• Job scheduling systems (using circular linked lists for round-robin scheduling).
Q31. Maximum in every sliding window of size K using deque class MaxSlidingWindow

{ static int[] maxSlidingWindow(int[] nums, int k) { Deque<Integer> deque = new

LinkedList<>(); int[] result = new int[nums.length - k + 1]; for (int i = 0; i <

nums.length; i++) { while (!deque.isEmpty() && deque.peek() < i - k + 1)

deque.poll(); while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i])

deque.pollLast();

deque.offer(i); if (i >= k - 1) result[i - k + 1] =

nums[deque.peek()];

return result;

Time: O(n), Space: O(k)

Q32. Largest rectangle in histogram class

LargestRectangleHistogram { static int

largestRectangleArea(int[] heights) { Stack<Integer>

stack = new Stack<>(); int maxArea = 0; for (int i =

0; i <= heights.length; i++) { int h = (i ==

heights.length) ? 0 : heights[i]; while (!stack.isEmpty()

&& h < heights[stack.peek()]) { int height =

heights[stack.pop()]; int width = stack.isEmpty() ? i


: i - stack.peek() - 1; maxArea =

Math.max(maxArea, height * width);

stack.push(i);

return maxArea;

Time: O(n), Space: O(n)

Q33. Explain the Sliding Window Technique in Array Problems. Provide examples and
applications.

The Sliding Window Technique is a powerful method used to optimize problems that involve
checking or computing values for all contiguous subarrays or substrings of a fixed or variable
size in an array or string.

Instead of recalculating the result for every subarray (which usually takes O(n × k) time), sliding
window reduces the time complexity to O(n) by maintaining a running window of size k and
updating it as the window moves through the array.

How It Works:

1. Define the start and end of the window (usually with two pointers).

2. Process the elements inside the window.

3. Slide the window forward by incrementing the pointers.

4. Update results accordingly without re-processing the whole subarray.

Types of Sliding Window:


• Fixed Size Window: Used when the subarray size is fixed.

• Variable Size Window: Used when the window size changes based on a condition (e.g.,
sum, character frequency, etc.).

Time and Space Complexity

• Time: O(n) – every element is processed at most twice (entering and exiting the
window).

• Space: O(k) or less, depending on the problem (e.g., using hash maps, deques, sets).

Applications of Sliding Window

1. Maximum / Minimum Sum Subarray of Size K

Find the maximum sum of any contiguous subarray of size k.

int maxSum = 0, windowSum = 0; for (int i =

0; i < k; i++) windowSum += arr[i]; for (int i

= k; i < n; i++) { windowSum += arr[i] -

arr[i - k];

maxSum = Math.max(maxSum, windowSum);

2. Counting Distinct Elements in a Window

Use a hash map or set to count distinct elements in each window of size k.

3. Longest Substring Without Repeating Characters

A common sliding window problem in strings using a dynamic window and hash set.

4. Smallest Subarray with Sum ≥ X

Variable window size problem used in optimization questions.

5. Binary Subarrays with Sum

Count the number of subarrays whose sum is equal to a given value using sliding window logic.
Real-World Use Cases

• Network traffic analysis – processing data over time intervals.

• Sensor data monitoring – analyzing trends in real-time.

• Streaming platforms – calculating watch time or behavior over recent intervals.

• Stock price analysis – moving average over recent days.

Q34. Subarray sum equal to K using hashing

class SubarraySumEqualsK { static int

subarraySum(int[] nums, int k) {

Map<Integer, Integer> map = new HashMap<>();

map.put(0, 1); int sum = 0, count = 0;

for (int num : nums) { sum += num;

count += map.getOrDefault(sum - k, 0);

map.put(sum, map.getOrDefault(sum, 0) + 1);

return count;

Time: O(n), Space: O(n)

Q35. K-most frequent elements using priority queue class

KMostFrequent { static int[] topKFrequent(int[] nums, int k) {


Map<Integer, Integer> map = new HashMap<>(); for (int num :

nums) map.put(num, map.getOrDefault(num, 0) + 1);

PriorityQueue<Map.Entry<Integer, Integer>> pq = new PriorityQueue<>((a, b) ->


a.getValue() - b.getValue()); for (Map.Entry<Integer, Integer> entry :
map.entrySet()) { pq.offer(entry); if (pq.size() > k) pq.poll();

int[] result = new int[k];

for (int i = k - 1; i >= 0; i--) result[i] = pq.poll().getKey();

return result;

Time: O(n log k), Space: O(n)

Q36. Generate all subsets of a given array class

Subsets { static List<List<Integer>> subsets(int[]

nums) { List<List<Integer>> result = new

ArrayList<>(); backtrack(result, new

ArrayList<>(), nums, 0); return result;

static void backtrack(List<List<Integer>> result, List<Integer> temp, int[] nums, int start) {

result.add(new ArrayList<>(temp)); for (int i = start; i < nums.length; i++) {

temp.add(nums[i]); backtrack(result, temp, nums, i + 1);

temp.remove(temp.size() - 1);

}
}

Time: O(2^n), Space: O(n)

Q37. All unique combinations that sum to a target class

CombinationSum { static List<List<Integer>> combinationSum(int[]

candidates, int target) { List<List<Integer>> result = new

ArrayList<>(); backtrack(result, new ArrayList<>(), candidates, target,

0); return result;

static void backtrack(List<List<Integer>> result, List<Integer> temp, int[] candidates, int

remain, int start) { if (remain == 0) result.add(new ArrayList<>(temp)); else if


(remain > 0) { for (int i = start; i < candidates.length; i++) {

temp.add(candidates[i]); backtrack(result, temp, candidates, remain -


candidates[i], i); temp.remove(temp.size() - 1);

Time: O(2^n), Space: O(n)


Q38. Generate all permutations of a given array

class ArrayPermutations { static

List<List<Integer>> permute(int[] nums) {

List<List<Integer>> result = new ArrayList<>();

backtrack(result, new ArrayList<>(), nums);

return result;

static void backtrack(List<List<Integer>> result, List<Integer> temp, int[] nums) {

if (temp.size() == nums.length) { result.add(new ArrayList<>(temp));

} else { for (int i = 0; i <

nums.length; i++) { if

(temp.contains(nums[i])) continue;

temp.add(nums[i]); backtrack(result,

temp, nums);

temp.remove(temp.size() - 1);

Time: O(n!), Space: O(n)

Q39. What is the Difference Between Subsets and Permutations? Provide Examples.
Subsets and Permutations are two fundamental concepts in combinatorics, but they are used in
different contexts and have different meanings:

🔹 Subsets

A subset is any combination of elements from a set, regardless of their order. The
key idea is: order doesn’t matter.

✅ Characteristics:

• Every element can either be included or excluded.

• A set with n elements has 2ⁿ subsets (including the empty set).

• Example: For the array [1, 2], the subsets are:


[], [1], [2], [1, 2]

📌 Used In:

• Power set generation

• Solving knapsack problems

• Finding combinations of items

• Backtracking-based problems

🔸 Permutations

A permutation is an ordered arrangement of elements. Here,


order matters.

✅ Characteristics:

• The number of permutations of n unique elements is n! (factorial of n).

• If selecting r elements out of n, the number of permutations is nPr = n! / (n - r)!

• Example: For the array [1, 2], the permutations are:


[1, 2], [2, 1]

📌 Used In:

• Problems involving arrangement/sequencing


• Scheduling, puzzles (like Sudoku), pathfinding

• Backtracking and recursive tree-based problems

✅ Key Differences

Feature Subsets Permutations

Order Matters ❌ No ✅ Yes


Duplicates Not allowed (unless specified) Not allowed unless specified
Total Count 2ⁿ n!

Example ([1,2]) [], [1], [2], [1,2] [1,2], [2,1]

Q40. Element with maximum frequency in array

class MaxFrequencyElement { static int

maxFrequency(int[] nums) {

Map<Integer, Integer> map = new HashMap<>();

int maxCount = 0, res = nums[0]; for (int num :

nums) { map.put(num,

map.getOrDefault(num, 0) + 1); if

(map.get(num) > maxCount) { maxCount =

map.get(num);

res = num;

}return res;

Time: O(n), Space: O(n)


Q41. Program to Find the Maximum Subarray Sum using Kadane’s Algorithm in Java public

class KadaneAlgorithm {

public static int kadane(int[] arr) {

int maxSoFar = Integer.MIN_VALUE;

int maxEndingHere = 0;

for (int num : arr) {

maxEndingHere = Math.max(num, maxEndingHere + num);

maxSoFar = Math.max(maxSoFar, maxEndingHere);

return maxSoFar;

public static void main(String[] args) {

int[] arr = {-2, 1, -3, 4, -1, 2, 1, -5, 4};

System.out.println("Maximum subarray sum is: " + kadane(arr));

}}

Time Complexity: O(n), where n is the number of elements in the array.

Space Complexity: O(1), as we only use a constant amount of extra space.

Q42. Explain the Concept of Dynamic Programming (DP) and Its Use in Solving the Maximum
Subarray Problem. Provide Examples.

🔹 What is Dynamic Programming (DP)?


Dynamic Programming (DP) is an algorithmic technique used to solve problems by breaking
them into smaller overlapping subproblems, solving each subproblem only once, and storing
the results (memoization) to avoid redundant calculations.

✅ Key Properties of DP Problems:

1. Overlapping Subproblems: The problem can be divided into subproblems that are
reused multiple times.

2. Optimal Substructure: The optimal solution to the problem can be constructed from
optimal solutions of its subproblems.

🔸 Application of DP: The Maximum Subarray Problem


The Maximum Subarray Problem involves finding the contiguous subarray (containing at least
one element) that has the largest sum in a given array of integers.

✅ Kadane’s Algorithm (A Classic DP Approach) Idea:

• For each element at index i, we decide:

o Either to include it in the existing subarray o

Or start a new subarray from this element

• We keep two variables:

o maxEndingHere → max subarray sum ending at

current index o maxSoFar → overall max sum found so

far

🔹 Kadane's Algorithm – Java Code Example public

int maxSubArray(int[] nums) {

int maxEndingHere = nums[0];

int maxSoFar = nums[0];

for (int i = 1; i < nums.length; i++) {


// Step 1: Either add to previous subarray or start new

maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);

// Step 2: Update global max maxSoFar =

Math.max(maxSoFar, maxEndingHere);

return maxSoFar;

🔸 Example Input:

text

CopyEdit

Input: [-2, 1, -3, 4, -1, 2, 1, -5, 4]

Output: 6

Explanation: The maximum subarray is [4, -1, 2, 1], which sums to 6.

✅ Why Kadane’s is Dynamic Programming?

• The solution to each subproblem (maxEndingHere[i]) depends on the solution to the


previous subproblem (maxEndingHere[i-1]).

• We store intermediate results and use them to build the final answer.

• Avoids recalculating subarray sums repeatedly.

🧠 Applications of DP (beyond Kadane’s):

• Fibonacci numbers

• Longest Common Subsequence (LCS)


• Knapsack problems

• Matrix Chain Multiplication

• Edit distance, Coin change

Q43. Solve the Problem of Finding the Top K Frequent Elements in an Array

Algorithm:

1. Count the frequency of each element in the array.

2. Use a min-heap (or priority queue) to store the k most frequent elements.

3. Pop elements from the heap to maintain only the k most frequent elements.

4. Return the k elements from the heap.

Program:

import java.util.*; public class TopKFrequentElements { public

static List<Integer> topKFrequent(int[] nums, int k) {

Map<Integer, Integer> countMap = new HashMap<>(); for

(int num : nums) { countMap.put(num,

countMap.getOrDefault(num, 0) + 1);

PriorityQueue<Map.Entry<Integer, Integer>> minHeap =

new PriorityQueue<>((a, b) -> a.getValue() - b.getValue());

for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {

minHeap.offer(entry);

if (minHeap.size() > k) {

minHeap.poll();

}
}

List<Integer> result = new ArrayList<>();

while (!minHeap.isEmpty()) {

result.add(minHeap.poll().getKey());

Collections.reverse(result); // Optional to get descending order

return result;

public static void main(String[] args) {

int[] nums = {1,1,1,2,2,3}; int k = 2;

List<Integer> result = topKFrequent(nums, k);

System.out.println("Top " + k + " frequent elements: " + result);

Time Complexity: O(n log k), where n is the number of elements in the array and k is the
number of top elements we need to find.
Space Complexity: O(n), where n is the number of unique elements in the array.

Q44. Find Two Numbers in an Array that Add Up to a Target Using Hashing

Algorithm:

1. Iterate through the array.

2. For each element, calculate its complement (target - current element).

3. If the complement exists in the hash set, return the pair.


4. Otherwise, add the current element to the hash set.

Program:

import java.util.*; public class TwoSum { public

static int[] twoSum(int[] nums, int target) {

Map<Integer, Integer> map = new HashMap<>();

for (int i = 0; i < nums.length; i++) { int

complement = target - nums[i]; if

(map.containsKey(complement)) { return

new int[] { map.get(complement), i };

map.put(nums[i], i);

return new int[] {};

public static void main(String[] args) {

int[] nums = {2, 7, 11, 15}; int target

= 9; int[] result = twoSum(nums,

target);

System.out.println("Indices of elements adding up to target: " + Arrays.toString(result)); }}

Time Complexity: O(n), where n is the number of elements in the array. Space
Complexity: O(n), as we are storing elements in a hash map.

Q45. Priority Queues and Their Applications in Algorithm Design

Priority Queue is a data structure where each element is associated with a priority, and the
element with the highest (or lowest) priority is dequeued first. It is often implemented using
heaps.
Applications in algorithm design:

1. Dijkstra's shortest path algorithm uses a priority queue to efficiently extract the
minimum distance node.

2. Huffman coding for data compression uses a priority queue to build the optimal coding
tree.

3. Merge k sorted lists: A priority queue can help merge multiple sorted lists in linear time.

Q46. Program to Find the Longest Palindromic Substring

Algorithm:

1. Use expand around center technique, where you check each character and expand
outward to check for both odd and even length palindromes.

2. For each character, expand around it as the center and track the longest palindrome.

Program:

public class LongestPalindromicSubstring {

public static String longestPalindrome(String s) {

if (s == null || s.length() == 0) return "";

int start = 0, end = 0;

for (int i = 0; i < s.length(); i++) { int len1 =

expandAroundCenter(s, i, i); // Odd length palindrome int len2 =

expandAroundCenter(s, i, i + 1); // Even length palindrome int len =

Math.max(len1, len2);
if (len > (end - start)) {

start = i - (len - 1) / 2;

end = i + len / 2;

return s.substring(start, end + 1);

private static int expandAroundCenter(String s, int left, int right) { while

(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {

left--;

right++;

return right - left - 1;

public static void main(String[] args) {

String s = "babad";

System.out.println("Longest palindromic substring: " + longestPalindrome(s));

Time Complexity: O(n^2), where n is the length of the string.


Space Complexity: O(1), as we are using only a constant amount of extra space.

Q47. Explain the Concept of Histogram Problems and Their Applications. Provide Examples.
🔹 What Are Histogram Problems?
Histogram problems are a class of computational problems that deal with bar heights (usually
represented as an array of integers), where each bar corresponds to a rectangle with a fixed
width (usually 1 unit) and a variable height.

These problems often involve finding optimal areas, analyzing shapes, or determining capacity
between the bars, and are commonly encountered in stack-based algorithm design.

🔸 Common Histogram Problems & Applications

1. Largest Rectangle in a Histogram

Problem:
Given an array of integers representing the heights of bars in a histogram, find the area of the
largest rectangle that can be formed from contiguous bars.

Approach:

• Use a stack to keep track of indices of increasing bar heights.

• Time Complexity: O(n)

Example Input: [2, 1, 5, 6, 2, 3]


Output: 10
Explanation: Largest rectangle is between heights 5 and 6 → area = 5 × 2 = 10

2. Trapping Rain Water Problem

Problem:
Given an array of non-negative integers where each element represents the height of a bar,
calculate how much rainwater can be trapped after raining.

Approach:

• Use two pointers or precomputed leftMax and rightMax arrays.

• Time Complexity: O(n)

• Space Complexity: O(1) (in two-pointer approach)

Example Input: [0,1,0,2,1,0,1,3,2,1,2,1]


Output: 6
Explanation: 6 units of water can be trapped between the bars.

Q48. Solve the Problem of Finding the Next Permutation of a Given Array

Algorithm:

1. Find the largest index i such that arr[i] < arr[i + 1]. If no such index exists, the array is the
last permutation.

2. Find the largest index j such that arr[j] > arr[i].

3. Swap arr[i] and arr[j].

4. Reverse the subarray starting at arr[i + 1].

Program:

import java.util.Arrays;

public class NextPermutation {

public static void nextPermutation(int[] nums) {

int i = nums.length - 2; while (i >= 0 && nums[i]

>= nums[i + 1]) i--;

if (i >= 0) { int j =

nums.length - 1; while

(nums[j] <= nums[i]) j--;

swap(nums, i, j);

reverse(nums, i + 1);

}
private static void swap(int[] nums, int i, int j) {

int temp = nums[i]; nums[i] = nums[j];

nums[j] = temp;

private static void reverse(int[] nums, int start) {

int end = nums.length - 1; while (start < end)

{ swap(nums, start, end); start++;

end--;

public static void main(String[] args) {

int[] nums = {1, 2, 3};

nextPermutation(nums);

System.out.println("Next permutation: " + Arrays.toString(nums));

Time Complexity: O(n), where n is the length of the array.


Space Complexity: O(1), since we modify the array in-place.

Q49. Find the Intersection of Two Linked Lists Algorithm:

1. Find the lengths of both linked lists.

2. Align the two lists by skipping the extra nodes in the longer list.

3. Traverse both lists in parallel and return the intersection node when found.

Program:

class ListNode {
int val;

ListNode next;

ListNode(int x) { val = x; }

public class IntersectionOfLinkedLists {

public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {

if (headA == null || headB == null) return null;

ListNode a = headA;

ListNode b = headB;

while (a != b) { a = (a == null)

? headB : a.next; b = (b == null)

? headA : b.next;

return a;

public static void main(String[] args) {

ListNode headA = new ListNode(4);

headA.next = new ListNode(1); ListNode

intersection = new ListNode(8);

headA.next.next = intersection; headB =


new ListNode(5); headB.next =

intersection;

ListNode intersectionNode = getIntersectionNode(headA, headB);

System.out.println("Intersection at node: " + intersectionNode.val);

}}

Time Complexity: O(n + m), where n and m are the lengths of the two linked lists. Space
Complexity: O(1), as we are using constant space.

Q50. Explain the Concept of Equilibrium Index and Its Applications in Array Problems. Provide
Examples.

🔹 What is an Equilibrium Index?

An Equilibrium Index in an array is an index i such that the sum of elements to the left of i is
equal to the sum of elements to the right of i.

Formally:

CopyEdit

A[0] + A[1] + ... + A[i-1] == A[i+1] + A[i+2] + ... + A[n-1]

🔸 Note: The element at index i itself is not included in either sum.


🔸 Example
text

CopyEdit

Input: A = [-7, 1, 5, 2, -4, 3, 0]

Equilibrium Index = 3

Explanation:

Sum of elements to the left of A[3] = -7 + 1 + 5 = -1

Sum of elements to the right of A[3] = -4 + 3 + 0 = -1

✅ How to Find Equilibrium Index (Efficient Approach)

1. Calculate the total sum of the array.

2. Initialize leftSum = 0.

3. Iterate through the array:

o At index i, calculate rightSum = totalSum - leftSum - A[i] o If leftSum

== rightSum, index i is an equilibrium index.

o Update leftSum += A[i]

🔸 Time Complexity: O(n)

🔸 Space Complexity: O(1)

📌 Applications of Equilibrium Index

1. Partitioning Arrays:

o Useful in problems where the array needs to be split into two parts with equal
sums.

o Can be used in game theory or balance problems.

2. Load Balancing: o In distributed systems, used to determine a balanced division of

workload/data.
3. Algorithm Design:

o Helps in solving problems related to prefix and suffix sums.

o Basis for solving equilibrium points in circular arrays or linked lists.

4. Interview Questions:

o Often asked in coding interviews as a test of understanding prefix sum,


optimization, and linear scanning.

You might also like