Greetings, readers! We are back with another series focused on Java coding interview questions and answers. Not all questions are coding though! If you've been following along, you may have found our previous questions helpful in your interview preparation. Get ready for more insights and tips to help you ace that Java interview!

To find duplicate characters in a string, we can use a HashMap to store the character and its count. Here is the code snippet:

String str = "Hello World";
char[] chars = str.toCharArray();
Map map = new HashMap();
for (char c : chars) {
   if (map.containsKey(c)) {
      map.put(c, map.get(c) + 1);
   } else {
      map.put(c, 1);
   }
}
for (Map.Entry entry : map.entrySet()) {
   if (entry.getValue() > 1) {
      System.out.println(entry.getKey() + " = " + entry.getValue());
   }
}

In this code, we are first converting the string to a char array. Then we are iterating through each character and storing its count in a HashMap. Finally, we are iterating through the HashMap and printing the characters that have a count greater than one.

2. How to find the second highest number in an array?

To find the second highest number in an array, we can sort the array in descending order and return the second element. Here is the code snippet.

int[] arr = { 3, 6, 2, 9, 7 };
Arrays.sort(arr);
System.out.println("Second highest number: " + arr[arr.length - 2]);

In this code, we are sorting the array in ascending order using the Arrays.sort() method. Then we are returning the second highest number by accessing the second last element in the array.

3. How to implement a stack using an array in Java?

This question tests your understanding of data structures and algorithms. A stack is a data structure that follows the Last In First Out (LIFO) principle. You can implement a stack using an array by keeping track of the top element and the size of the stack. Here is a code solution:

public class ArrayStack {
    private int[] arr;
    private int top; // Index of the top element
    private int size; // Number of elements in the stack
public ArrayStack(int capacity) {
        arr = new int[capacity];
        top = -1; // Initialize top to -1 because the stack is empty
        size = 0;
    }
    // Add a new element to the top of the stack
    public void push(int val) {
        if (size == arr.length) {
            throw new RuntimeException("Stack is full");
        }
        arr[++top] = val; // Increment top and assign the new element to the corresponding position in the array
        size++;
    }
    // Remove and return the top element of the stack
    public int pop() {
        if (size == 0) {
            throw new RuntimeException("Stack is empty");
        }
        size--; // Decrement size because we're removing an element
        return arr[top--]; // Decrement top and return the corresponding element in the array
    }
    // Return the top element of the stack without removing it
    public int peek() {
        if (size == 0) {
            throw new RuntimeException("Stack is empty");
        }
        return arr[top];
    }
    // Check if the stack is empty
    public boolean isEmpty() {
        return size == 0;
    }
    // Return the number of elements in the stack
    public int size() {
        return size;
    }
}

The ArrayStack class represents a stack implemented using an array. It has three private instance variables: arr for the underlying array, top for the index of the top element, and size for the size of the stack.

The push method adds a new element to the stack by incrementing the top index and assigning the new element to the corresponding position in the array. The pop method removes and returns the top element of the stack by decrementing the top index and returning the corresponding element in the array. The peek method returns the top element of the stack without removing it. The isEmpty method checks if the stack is empty. The size method returns the size of the stack.

4. How to find the largest and smallest number in an array of integers in Java?

This question tests your understanding of basic array manipulation and algorithm design. One way to find the largest and smallest numbers in an array is to iterate through the array and keep track of the maximum and minimum numbers seen so far. Here is a code solution:

int[] arr = {3, 5, 1, 4, 2};
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
// Find the maximum and minimum numbers
for (int num : arr) {
    if (num > max) {
        max = num;
    }
    if (num < min) {
        min = num;
    }
}
System.out.println("Largest number: " + max);
System.out.println("Smallest number: " + min);

In this code, we first create an array arr of integers. We then initialize max and min to the smallest and largest possible integers, respectively. We then iterate through the array and update max and min accordingly. Finally, we print the largest and smallest numbers.

5. Find the kth largest element in an unsorted array

Finding the kth largest element in an unsorted array is a common Java coding interview question that requires a good understanding of sorting algorithms. One way to solve this problem is by using the Quickselect algorithm, which is a modified version of the Quicksort algorithm. Here's how you can do it:

public static int findKthLargest(int[] arr, int k) {
    int left = 0;
    int right = arr.length - 1;
    while (true) {
        int pivotIndex = partition(arr, left, right);
        if (pivotIndex == k - 1) {
            return arr[pivotIndex];
        } else if (pivotIndex > k - 1) {
            right = pivotIndex - 1;
        } else {
            left = pivotIndex + 1;
        }
    }
}
private static int partition(int[] arr, int left, int right) {
    int pivot = arr[right];
    int i = left - 1;
    for (int j = left; j < right; j++) {
        if (arr[j] >= pivot) {
            i++;
            swap(arr, i, j);
        }
    }
    swap(arr, i + 1, right);
    return i + 1;
}
private static void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

The above code implements the findKthLargest method that takes an int array and an int k as input and returns the kth largest element in the array. It uses the Quickselect algorithm to partition the array around a pivot element, and recursively calls itself on the subarray that contains the kth largest element. The partition method is a helper method that partitions the array using the last element as the pivot and returns the index of the pivot element. The swap method is a helper method that swaps two elements in the array.

6. Implement a LRU Cache

Implementing an LRU (Least Recently Used) Cache is another common Java coding interview question that requires a good understanding of data structures. Here's how you can do it!

import java.util.HashMap;
import java.util.Map;
public class LRUCache {
    private final int capacity;
    private final Map> map;
    private final Node head;
    private final Node tail;
    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.map = new HashMap<>();
        this.head = new Node<>(null, null);
        this.tail = new Node<>(null, null);
        this.head.next = tail;
        this.tail.prev = head;
    }
    public V get(K key) {
        if (!map.containsKey(key)) {
            return null;
        }
        Node node = map.get(key);
        remove(node);
        addFirst(node);
        return node.value;
    }
    public void put(K key, V value) {
        if (map.containsKey(key)) {
            Node node = map.get(key);
            node.value = value;
            remove(node);
            addFirst(node);
        } else {
            if (map.size() == capacity) {
                map.remove(tail.prev.key);
                remove(tail.prev);
            }
            Node node = new Node<>(key, value);
            map.put(key, node);
            addFirst(node);
        }
    }
    private void remove(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
    private void addFirst(Node node) {
        node.next = head.next;
        node.prev = head;
        head.next.prev = node;
        head.next = node;
    }
    private static class Node {
        private final K key;
        private V value;
        private Node prev;
        private Node next;
        private Node(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }
}

The above code implements an LRU Cache using a doubly linked list and a hash map. The LRU Cache has a fixed capacity and evicts the least recently used item when the cache is full. The LRUCache class takes two type parameters, K for the key and V for the value. The capacity field stores the maximum number of items that the cache can hold. The map field stores a hash map that maps keys to nodes in the linked list. The head and tail fields are dummy nodes that mark the beginning and end of the linked list.

The get method takes a key as input and returns the corresponding value from the cache. If the key is not present in the cache, it returns null. If the key is present in the cache, it removes the corresponding node from the linked list and adds it to the front of the list using the remove and addFirst methods, respectively.

The put method takes a key and value as input and inserts them into the cache. If the key is already present in the cache, it updates the corresponding value and moves the corresponding node to the front of the list using the remove and addFirst methods, respectively. If the key is not present in the cache and the cache is full, it removes the least recently used item from the cache and inserts the new key-value pair at the front of the list using the remove, addFirst, and map.remove methods.

The remove method removes a node from the linked list by updating the prev and next pointers of its neighboring nodes. The addFirst method adds a node to the front of the linked list by updating the next and prev pointers of the node and its neighboring nodes. The Node class is a private inner class that represents a node in the linked list. It contains a key-value pair and prev and next pointers that point to the previous and next nodes in the linked list.

Overall, this implementation provides O(1) time complexity for both get and put operations by using a hash map to provide constant-time lookups and a doubly linked list to provide constant-time insertions and deletions at the front of the list.

7. What is the difference between List.of() and Arrays.asList() in Java 11?

Both List.of() and Arrays.asList() can be used to create an immutable list. However, there are a few differences between them. List.of() returns a true immutable list that cannot be modified, while Arrays.asList() returns a fixed-size list that can be modified if the underlying array is modified. Also, List.of() can take any number of arguments and returns an unmodifiable list, while Arrays.asList() takes an array as an argument and returns a mutable list backed by the array. For example.

List immutableList = List.of("foo", "bar");
immutableList.add("baz"); // will throw an UnsupportedOperationException
List mutableList = Arrays.asList("foo", "bar");
mutableList.add("baz"); // will work fine, but will modify the underlying array

8. What is the difference between flatMap() and map() in Java 11?

Answer: Both flatMap() and map() are used to transform elements in a stream. However, the main difference is that flatMap() is used to flatten a stream of streams into a single stream, while map() is used to transform each element in a stream into another element. For example:

List> nestedList = Arrays.asList(Arrays.asList("foo", "bar"), Arrays.asList("baz"));
List flatList = nestedList.stream().flatMap(List::stream).collect(Collectors.toList());
// flatList contains ["foo", "bar", "baz"]
List transformedList = Arrays.asList("foo", "bar").stream().map(String::toUpperCase).collect(Collectors.toList());
// transformedList contains ["FOO", "BAR"]

9. What is the difference between synchronized and Lock in Java?

Both synchronized and Lock are used to provide mutual exclusion and prevent data races in multi-threaded code. However, there are a few differences between them. synchronized is a built-in keyword in Java that provides intrinsic locking and is easier to use and understand, but can lead to performance issues in highly-contended code. On the other hand, Lock is a more flexible and powerful tool for synchronization that can provide features such as fairness, reentrant locking, and timeout capabilities, but requires more complex code and can be harder to use and understand.

10. What is the difference between a HashSet and a LinkedHashSet in Java?

Answer: Both HashSet and LinkedHashSet are implementations of the Set interface in Java. However, there are a few differences between them. HashSet is an unordered set that uses a hash table to store its elements, providing constant-time performance for basic operations such as add(), contains(), and remove(), but does not maintain any order of the elements. On the other hand, LinkedHashSet is an ordered set that uses a hash table and a linked list to store its elements, providing constant-time performance for basic operations and maintaining the order of the elements in which they were added.

Bonus question!

11. What is the purpose of the default keyword in Java 8 interfaces?

Answer: In Java 8 and above, interfaces can contain default methods, which are methods with a body that provide a default implementation for the method. The default keyword is used to indicate that a method is a default method. This allows interfaces to evolve without breaking existing implementations that may not have implemented the new method. Default methods can also be overridden by implementing classes if they want to provide a different implementation. For example:

public interface MyInterface {
    void doSomething();
default void doSomethingElse() {
        System.out.println("Doing something else...");
    }
}
public class MyClass implements MyInterface {
    public void doSomething() {
        System.out.println("Doing something...");
    }
    public void doSomethingElse() {
        System.out.println("Doing something else differently...");
    }
}

In this example, MyClass implements MyInterface and overrides the doSomethingElse() default method to provide a different implementation.

If you haven't already read the previous parts of similar Java interview questions, please refer to the following posts.

Java coding interview questions and answers — part 3

Java coding interview questions and answers — part 2

Java coding interview questions and answers — part 1

If you're interested in joining Medium, please use my personal referral link to become a member. You'll get unlimited access to great content and supportive community and a platform that values quality content.

Thanks for reading! Good luck.