  # Coding Interview Questions and Answers for 2023 Programming

An interview for the role of developer always includes coding questions. No matter the programming language you learn, it's always expected of you to be familiar with the fundamentals of programming. If you are looking for coding interview questions, this article covers the basic programming questions and advanced coding questions required for cracking the coding interview. The basic coding questions cover the coding questions for placement and the coding questions asked in interviews.

• 4.7 Rating
• 50 Question(s)

## Beginner

In computer systems, a data structure is a method that helps to store and efficiently retrieve data. Data can take many different forms, and to store and retrieve it effectively, we must have a solid grasp of data structures. Data structures come in a variety of formats, and we must choose the best one for the task at hand. For instance, you would utilise the appropriate data structure type if you needed to store data that was ordered or unordered, had a fixed length or variable length, or both. Some of the most common data structures used by programmers are:

1. Arrays: It is one of the simplest forms of data structure which stores a series of items in a sequential manner.
2. Linked Lists: A linked list is a linear data structure made up of nodes, each of which houses a data value and a reference to the node after it.
3. Stacks: Stacks can be visualised as a stack or pile of books stacked on top of one another, with the last item in the pile being accessed first, according to the LIFO (Last In First Out) order.
4. Queues: The best illustration of a queue data structure is a line of people standing in line, wherein the first person to enter the queue is also the first person to leave it, according to the FIFO (First In First Out) principle.
5. Hash Tables: Hash tables are the ideal data structure to store data items that follow after a key-value pair. A key can be used to refer to or access any item in the table. For instance, if the key is "Student Name," the value of the key will be the student's name.

Programmers are responsible for solving logical problems through critical thinking. They are not required to know any programming language or syntax. Their responsibility is to prepare the algorithm or even the pseudo-code. On the other hand, coders are responsible to write the logic or algorithm in a specific programming language. They can understand the syntaxes, optimize the code, debug and run test cases, and use different libraries and modules. You can consider that defining an algorithm for a data structure is the task of a programmer while implementing the data structure in a specific programming language like Java, C++, Python, etc. is the task of the coder. It is generally preferred that a coder should be a good programmer.

Arrays are the simplest data structures. Almost all the programming languages have an in-built implementation of an array (it might come with slight modification). An array can be understood as a box of cookies placed in a single row one after the other. Each cookie is an element or item. Each cookie in the box is next to the other just like elements in an array. Each cookie can be identified with a unique location and so the items are in an array. However, the position of the items in an array starts with index 0 followed by 1, 2, 3, and so on. The size of the array is fixed just like the cookie box. You cannot add more cookies once the box is full. Therefore, arrays have static memory allocation but however one can also implement a dynamic array as per the usage. A cookie box will only contain cookies and not cake or another item. Similarly, an array contains a single data type i.e., it is homogeneous. However, we can also have heterogeneous array types as well. For example, python lists mimic an array data structure but come with variable length and the ability to store a variety of data types making it heterogeneous. The below image demonstrates an array of lengths equal to 10 and therefore, the index position ranges from 0 to 9. LIFO stands for Last In First Out. The idea follows from the stack of items. For example, a stack of books is placed on a table. Considering you want to add a new book to the stack, the ideal way will be to place the book on top of the stack. Now, to access the stack you have to first remove the top-most book which is nothing but the most recent addition to the stack. Hence, the stack follows the last in first out order. Stack is a widely used data structure that provides a way of accessing, storing and retrieving data. The FIFO or First In First Out order comes from the idea of queues. A queue of people standing in line means that the person at the start of the line will be the first one to leave the queue. There are a lot of real-life examples of queues like the queue during the security check in an airport. Similarly, in a queue data structure, the data that is stored first is retrieved first. This is in contrast to a stack where the first item is the last to leave the stack during retrieval. An algorithm is a set of steps taken to accomplish a task. For example, if you are preparing vegetable soup, you will follow certain steps to ensure your food is prepared just right. You might first chop vegetables, then heat oil in a pot, followed by placing all the vegetables in the pot and frying it, then finally adding some water and waiting for some time. So here we performed a series of tasks to arrive at an outcome, Similarly, in computer science, learning about different types of algorithms and knowing when to apply them allows us to write time and memory-efficient programs. For example, Google maps use an algorithm to find the fastest path to reach the destination, compression software uses certain algorithms to reduce the memory consumption of files, and logistics and supply chain solutions use optimization algorithms to efficiently manage the movement of their goods. There is no best algorithm. Each of these algorithms is designed keeping specific use cases in mind and therefore, one must be aware of when to use them.

Recursion is a process in which a solution (implemented in the form of a function) calls itself recursively to solve sub-parts of the same problem. Therefore, the function is calling itself recursively to arrive at the final solution. One point to be noted here is that one needs to provide a condition to terminate the recursion cycle. Using recursion results in a reduced length of the code since we are using the same code recursively. Algorithms like DFS of Graph, Towers of Hanoi (TOH), etc., use recursion for their implementation. The prime example of a recursion problem is the factorial of a number. During the calculation of the factorial of a number, we call the same function recursively with an input number lesser than the previous one so that eventually we multiply all the natural numbers lesser than the provided number. The program terminates when the number is equal to 1 or 0.

Linear data structures are the ones which follow a sequential structure. Each element in a sequence is attached to the previous and (or) next element forming a linear structure. It follows a single-level hierarchy and therefore, we can iterate through each of the elements in a single loop. Also, the elements are sequentially organized in the computer memory. Some examples of a linear data structure are arrays, linked lists, stacks, queues, etc.

Unlike linear data structures, non-linear data structures follow a multi-level hierarchical structure. Since more than one level is involved, traversing through them requires more than one run or loop. Due to this complexity, they are difficult to implement in comparison to linear data structures. However, they are known to utilize computer memory efficiently compared to their linear counterparts. Some examples of non-linear data structures are binary trees, graphs, etc.

IDE or Integrated Development Environment provides a software or application development environment. There are tons of IDE available on the internet with each of them providing its own set of features. IDE is meant to provide a fluid UI, an effortless coding environment for one or more programming languages, and other third-party add-ons like themes, tools, etc. According to Google trends, Visual Studio Code and Visual Studio (popular for Visual Basic) are the most searched IDE on the internet. Visual Studio Code has increasing popularity due to its user-friendly UI, faster loading, git integration, rich marketplace, and freeware, and is backed by Microsoft. However, IDEs like PyCharm, and Eclipse help to effortlessly work on a particular programming language or framework due to their intelligence engine which can identify errors and also provide suggestions in real-time. However, one can also use online compiler for any quick check of their code.

A binary tree data structure is a non-linear tree-like structure observed in a tree data structure. While tree data structure has no restrictions on the number of child nodes, binary tree data structures have only 2 child nodes. Therefore, each node has a value and reference to its right and left child nodes. It is suitable for tasks like searching and sorting. It is easier to traverse in a binary tree structure as compared to other tree structures.

The pseudocode to find the missing number in an array that contains the first ‘n’ integers are –

• Step 1: INITIALIZE an array with the first ‘n’ integers and a missing number.
• Step 2: COMPUTE the sum of the first ‘n’ natural numbers using the formula [n*(n+1)]/2.
• Step 3: COMPUTE the sum of the integers present in the array.
• Step 4: SUBTRACT the output of Step 4 from the output of Step 3 and the result will be the missing number.

In a python programming language, the same can be implemented as –

```# Initialize the array
arr = [1, 2, 3, 4, 5, 6, 7, 9, 10]
# Compute the sum of first n natural numbers
n = len(arr) + 1
sum_n = n * (n + 1) / 2
# Compute the sum of the integers in the array
sum_arr = 0
for num in arr:
sum_arr += num
# Subtract sum_arr from sum_n
missing_num = sum_n – sum_arr
missing_num = int(missing_num)
print(‘The missing number is’, missing_num) ```

The output of the above program will be “The missing number is 8”.

The pseudocode to reverse a string is –

• Step 1: INITIALIZE the input string with a value that needs to be reversed
• Step 2: DECLARE an empty string variable that will store the reversed string
• Step 3: Start a FOR LOOP to iterate over each character of a string
• Step 4: CONCATENATE each character with the declared variable at the start
• Step 5: END FOR LOOP
• Step 6: DISPLAY the reversed string

In a python programming language, the same can be implemented as –

```# Initialize the input string
input_string = “Hello World”
# Initialize an empty string
output_string = “”
# Loop through the input string
for char in input_string:
output_string = char + output_string
print(output_string) ```

The output of the above program will be “dlroW olleH”.

The pseudocode to find the largest element in an integer array is –

• Step 1: INITIALIZE the array.
• Step 2: ASSIGN a random element from the array as the largest element.
• Step 3: ITERATE through each element of the array.
• Step 4: IF the element is greater than the assigned largest element then reassign the largest element to the current element.

In a python programming language, the same can be implemented as –

```# Initialize the input array
arr = [56, 63, 84, 90, 15, 38, 22, 5, 71, 49]
# Assign a random element as the largest number
largest_element = arr
# Loop through each element in the array
for ele in arr:
# Check if the element is greater than the assigned largest
if ele > largest_element:
# Re-assign the largest to the current element
largest_element = ele
print(‘Largest element:’, largest_element) ```

The output of the above program will be ‘Largest element: 90’

A palindrome string reads the same when reversed. For example, ‘radar’ is a palindrome string which reads as ‘radar’ even when reversed. The word ‘rider’ is not a palindrome string since it does not read the same when reversed (‘redir’). While implementing a palindrome string, we will check the first character with the last one if they are the same, followed by the second character and second last character, and so on until we reach the centre of the string. The equivalent code for this can be implemented in python as –

```# Initialize the input string
input_string = input_string.lower()
str_length = len(input_string)
# Assign a palindrome flag to True
palindrome_flag = True
for idx in range(0, int(str_length / 2)):
if input_string[idx] != input_string[str_length – idx - 1]:
palindrome_flag = False
break
if palindrome_flag:
print(f‘{input_string} is a palindrome string’)
else:
print(f‘{input_string} is not a palindrome string’) ```

The output of the above program will be “radar is a palindrome string”.

There are 5 alphabets representing vowels while the rest of the alphabets among the 26-letter alphabets are called consonants. We will iterate through each character in the input string. A counter needs to be initialized which will increment every time it iterates through a vowel. This will give us the count of the number of vowels in a string. The count of number of consonants can be derived from the vowel count and the length of the string. This can be implemented in python as –

```input_string = 'assembly language'
input_string = input_string.lower()
vowel_list = ['a', 'e', 'i', 'o', 'u']
str_length = len(input_string)
vowel_count = 0
for idx in range(0, str_length):
if input_string[idx] in vowel_list:
vowel_count += 1
print(f'There are {vowel_count} vowels and {str_length - vowel_count} consonants in the string') ```

The output of the above program will be “There are 6 vowels and 11 consonants in the string”.

A queue is a linear data structure that is based on the FIFO (First In First Out) order. Enqueue and dequeue are two of the basic operations that can be performed on a queue along with another set of operations. An enqueue operation will insert a new element at the end of the queue while a dequeue operation removes (pops) and returns the element that has occupied the start (front) of the queue. A linked list is a linear data structure that consists of nodes in sequence to store a collection of data elements dynamically. Each node contains a value and a reference pointer (link) to the next node. Unlike arrays, linked lists are not stored in contiguous memory locations. Therefore, these reference pointers are required to direct to the next node value. The size of a linked list can grow and shrink dynamically, thus, avoiding any wastage of memory space. The reference pointer of the last node in the sequence is null since it does not point to any further node in the sequence. To find the number of occurrences of a character in a given string, we will iterate through the string and create a counter for the character. Whenever the iteration results in a match with the character, we will increment this counter by 1. This can be implemented in python as –

```input_string = “coding interview preparation”
input_string = input_string.lower()
character = ‘i’
str_length = len(input_string)
char_count = 0
for idx in range(0, str_length):
if input_string[idx] == character:
char_count += 1
print(f‘There are {char_count} occurrences of {character} in the input string’) ```

The output of the above program will be “There are 4 occurrences of i in the input string”.

Reversing an array through swapping requires the interchange of the values of two different locations (placed symmetrically) in an array with the help of a temp variable. The pseudocode can be written as –

1. Step 1: ASSIGN two pointers at the start and end of the array.
2. Step 2: SWAP the two values represented by the two assigned pointers.
3. Step 3: Increment the first (start) pointer by 1 and decrement the second (end) pointer by 1.
4. Step 4: Continue if the start pointer index is not greater than or equal to the end pointer index.

This can be implemented in python as –

```input_arr = [1, 2, 3, 4, 5]
arr_length = len(input_arr)
start = 0
end = arr_length - 1
while start < end:
temp = input_arr[start]
input_arr[start] = input_arr[end]
input_arr[end] = temp
start += 1
end -= 1
print(‘Reversed Array:’, input_arr) ```

The output of the above python program is “Reversed Array: [5, 4, 3, 2, 1]”

A library is a set of pre-defined functions that can be used to achieve a task. The tasks that otherwise would require writing multiple lines of code can be accomplished with just a fraction of code lines. For example, the python Pandas library is capable of performing a lot of operations on tabular data like CSV, such as ordering, grouping, sorting, imputing values, deleting records, performing complex calculations, creating charts and graphs, etc. There are also libraries which can perform tasks like rgb to hex code conversion, qrcode creation, convert binary code to ascii code, etc. If we tried implementing these operations without using the library, it will multiply the implementation time by a big number and most importantly it is not required. We can save this time and focus on the specific logic designed for the application. Therefore, to perform the common operations with fewer lines of code and avoid unnecessary development time, we can prefer using available libraries.

A framework can be considered a superset of libraries. In computer programming, a framework is a basic structure based on a concept that helps to build software quickly and efficiently. It consists of pre-defined functions, methods, classes, and variables that can be utilized to build the application. A framework serves a specific purpose for development. For example, Django and Flask are Python frameworks that help to build server-side applications while React JS and Angular are JavaScript frameworks that help with frontend application development.

Numerous high-level programming languages are based on interpreters, compilers, or a combination of the two. The work of translating machine code from high-level language to low-level language is carried out by both the compiler and the interpreter, but they approach it in different ways. The complete high-level program is translated at once by the compiler from high-level language to machine code. Due to this, there may be some translation time, but the execution follows quickly. Unfortunately, the program will not function if there is a bug in it. On the other hand, the interpreter will translate each command in the high-level language code before executing it on its own. In this case, the translation is quick but the actual execution is slow. The main benefit of interpreters is that output is produced after each instruction and they continue running until an error occurs.

We know that, a number (natural numbers excluding 1) is said to be prime number if it is only divisible by 1 and itself. The pseudocode for the program is –

• Step 1: TAKE INPUT from the user
• Step 2: ASSIN a flag to indicate if a number is not prime and set it with false value
• Step 3: CHECK IF the number is greater than 1, else the input is invalid. Exit the program.
• Step 4: ITERATE over a loop from 2 to number – 1.
• Step 5: CHECK IF the number is divisible by any of these iterations. If yes, then set the flag to True. Break the loop
• Step 6: DISPAY the output.

This can be implemented in python –

```# Take input from user
num = int(input("Enter a number: "))
# Assign the flag
flag = False
if num > 1:
# Check if the number is divisible
# by another number except 2 and itself.
for i in range(2, num):
if num % i == 0:
# Set the flag to True i.e. not prime
flag = True
# Break the loop
break
if flag:
print(num, "is a prime number")
else:
print(num, "is not a prime number") ```

The output of the program is –

Enter a number: 29

29 is not a prime number

The pseudocode for finding the prime factors of an integer –

• Step 1: TAKE INPUT from the user
• Step 2: ITERATE from 3 to square root of the number
• Step 3: CHECK IF the number is divisible by the iterator. If yes, then display the number.
• Step 4: DISPLAY the final indivisible value.

The python program for the same is –

```# Take input from user
num = int(input("Enter a number: "))
for i in range(2, int(num**0.5)):
while num % i == 0:
print(i, end = " ")
num //= i
print(num) ```

The output of the program is –

Enter a number: 153

3 3 17

In case of an Armstrong number of 3 digits, the sum of cubes of each digit is equal to the number itself. For example, 153 is an Armstrong number (1 x 1 x 1 + 5 x 5 x 5 + 3 x 3 x 3 = 153). To implement this, we need to iterate every digit and calculate its cube and add it to the resultant. The pseudocode is given as –

• Step 1: TAKE INPUT from the user
• Step 2: ASSIGN the resultant sum value to 0
• Step 3: COPY num value to a temporary variable (to allow comparison at end)
• Step 4: RUN WHILE LOOP until temp becomes equal to or less than 0.
• Step 5: COMPUTE the last digit
• Step 6: COMPUTE the cube of this digit and add it to the resultant sum variable
• Step 7: Perform integer division by 10 to eliminate the last digit
• Step 8: CHECK IF the resultant sum is equal to the number and display the result accordingly

The python implementation for the same is –

```# Take input from user
num = int(input("Enter a number: "))
# Assign the sum to 0
sum_ = 0
# Assign temp as num
temp = num
while temp > 0:
# Get the last digit
digit = temp % 10
# Add its cube to the resultant
sum_ += digit * digit * digit
# Perform integer division by 10
temp //= 10
if num == sum_:
print(num,"is an Armstrong number")
else:
print(num,"is not an Armstrong number") ```

The output of the program is –

Enter a number: 153

153 is an Armstrong number

A year is a leap year if it is divisible by 400 or divisible by 4 but not by 100 since every 4th century year is a leap year. The pseudocode can be given as –

• Step 1: TAKE INPUT from the user
• Step 2: CHECK IF the year is divisible by 400. If yes, then DISPLAY that the year is a leap year and exit.
• Step 3: CHECK IF the year is divisible by 4 and not divisible by 100. If yes, then DISPLAY that the year is a leap year and exit.
• Step 4: DISPLAY that the year is not a leap year.

The python implementation for the same is –

```# Take input from user
year = int(input("Enter a number: "))
if year % 400 == 0:
print(year, 'is a leap year')
elif year % 100 != 0 and year % 4 == 0:
print(year, 'is a leap year')
else:
print(year, 'is not a leap year')
The output of the program is – ```

Enter a number: 2100

2100 is not a leap year

The bubble sort is the simplest way of sorting which is sometimes called sinking sort. In a bubble sort, we repeatedly compare each pair of adjacent elements and swap them if they are in the wrong order. We repeat this process until all elements get sorted. Let us use an example to understand this example clearly. Consider the following array. We will compare the first two elements in the array, i.e., 56 (index 0) and 63 (index 1). If the left element (at a lesser index) is greater than the right element (at a greater index), we will swap the numbers otherwise ignore them. So, in the first comparison between 56 and 63, we ignore them. During the second comparison, we compare 63 (index 1) and 84 (index 2). Again, the element at the lower index, that is, 63 is smaller than the element at the higher index, 84, so we ignore them. During the comparison of 22 (index 2) and 84 (index 3), we notice that the element at index 2 is greater than the element at index 3 so we swap the two numbers. The below image represents the complete first iteration during the bubble sorting of the above array. The coloured elements are the ones which are taken into consideration during the comparison. The elements coloured in light blue represent that the items are not swapped after comparison. The elements coloured in orange represent that the element was swapped after comparison. Finally, we get an array in which the last item (84 coloured in red) is frozen and it won’t be considered for any further sorting operation. Now, during the second set of iterations, the second highest number will get sorted. During each successive iteration, it will not consider the frozen elements from previous iterations. The further iterations for the sorting are – The pseudocode to implement a bubble sort algorithm is –

1. Step 1: INITIALIZE an array with integer elements.
2. Step 2: LOOP through integers (i) ranging from index 0 to one short of the length of the array. (So that we do not encounter index error while comparing the last two elements in the array)
3. Step 3: LOOP through integers (j) ranging from index 0 to (length of array – i – 1). (This ensures we are not considering the frozen elements)
4. Step 4: Compare the elements in an array at index position j and j+1. If the element at index position j is greater than the element at index position j+1, then swap the elements, else continue to the next pass.
5. This can be implemented in python as –
```input_arr = [56, 63, 84, 22, 71, 49]
arr_length = len(input_arr)
for i in range(0, arr_length – 1):
for j in range(0, arr_length – i – 1):
if input_arr[j] > input_arr[j+1]:
temp = input_arr[j]
input_arr[j] = input_arr[j+1]
input_arr[j+1] = temp
print(‘Sorted Array:’, input_arr) ```

The output of the above program is “Sorted Array: [22, 49, 56, 63, 71, 84]”.

A stack data structure can be imagined as a pile of objects stacked vertically. When we make an addition to the stack, it is added to the top and while accessing the stack, the last added object to the stack is the first to be accessed. The common stack operations are:

• push – To insert a new element into the stack.
• pop – To remove and return the value of the last added element to the stack.
• isEmpty – Checks whether the stack is empty or not. It returns true if the stack is empty, else false.
• isFull – Checks whether the stack is full. It returns true if the stack is full, else false.
• delete – Deletes a stack.
• size – Returns the size of the stack.
• peek – Returns the value of the element present at the top of the stack.

The stack can be implemented in python using the code –

```class Stack:
# Initialize the stack with the provided length
def __init__(self, length):
self.stack = []
self.length = length
self.__size = 0
def size(self):
'''
Returns the current size of the stack
'''
return self.__size
def isEmpty(self):
'''
Returns True if the stack is empty, else False
'''
return self.__size == 0
def isFull(self):
'''
Returns True if the stack is full, else False
'''
return self.length == self.__size
def push(self, element):
'''
Adds a new element to the stack if there is a space.
'''
if not self.isFull():
self.stack.append(element)
self.__size += 1
print(f'Successfully added {element} to the stack.')
else:
print('Stack is full. New element cannot be added to the stack.')
def pop(self):
'''
Removes and returns the value of an element present at top of the stack, if the stack is not empty.
'''
if not self.isEmpty():
element = self.stack.pop(-1)
self.__size -= 1
print('Successfully removed element from top of the stack.')
return element
print('Stack is empty. Nothing to pop from the stack.')
def peek(self):
'''
Returns the value of the element present at the top of the stack if the stack is not empty.
'''
if not self.isEmpty():
return self.stack[-1]
print('Stack is empty. Nothing to peek in the stack.')
def delete(self):
'''
Deletes the stack
'''
self.stack = None
# Create a new stack with length = 5
s = Stack(length = 5)
# Pop item from the stack
print(s.pop())
# Check if the stack is empty
print(s.isEmpty())
# Peek item from the stack
print(s.peek())
# Push 3 items to the stack
s.push(30)
s.push(40)
s.push(55)
# Check the size of the stack
print(s.size())
# Push two more elements to the stack
s.push(60)
s.push(85)
# Peek in the stack and print the response
print(s.peek())
# Add one more item to the stack
s.push(100)
# Check if the stack is full
print(s.isFull())
# Pop an item from the stack
print(s.pop()) ```

The output of the program is –

```Stack is empty. Nothing to pop from the stack.
None
True
Stack is empty. Nothing to peek in the stack.
None
Successfully added 30 to the stack.
Successfully added 40 to the stack.
Successfully added 55 to the stack.
3
Successfully added 60 to the stack.
Successfully added 85 to the stack.
85
Stack is full. New element cannot be added to the stack.
True
Successfully removed element from top of the stack.
85 ```

A queue is a data structure that stores items in a first-in-first-out (FIFO) order just like a queue of persons standing. The common queue operations are:

• enqueue – Add a new element to the end of the queue.
• dequeue – Remove and return the value of the element at the front of the queue.
• peek – Return the value of the element at the front of the queue.
• delete – Delete the queue.
• isEmpty – Checks if the queue is empty or not.
• isFull – Checks if the queue is full or not
• size – Returns the size of the queue.

The queue can be implemented in python using the code –

class Queue:

```# Initialize the queue with the provided length
def __init__(self, length):
self.queue = []
self.length = length
self.__size = 0
def size(self):
'''
Returns the current size of the queue
'''
return self.__size
def isEmpty(self):
'''
Returns True if the queue is empty, else False
'''
return self.__size == 0
def isFull(self):
'''
Returns True if the queue is full, else False
'''
return self.length == self.__size
def enqueue(self, element):
'''
Adds a new element to the queue if there is a space.
'''
if not self.isFull():
self.queue.append(element)
self.__size += 1
print(f'Successfully added {element} to the queue.')
else:
print('Queue is full. New element cannot be placed in the queue.')
def dequeue(self):
'''
Removes and returns the value of an element present in the front of the queue, if the queue is not empty.
'''
if not self.isEmpty():
element = self.queue.pop(0)
self.__size -= 1
print('Successfully removed element from front of the queue.')
return element
print('Queue is empty. Nothing to dequeue.')
def peek(self):
'''
Returns the value of the element present in the front of the queue if the queue is not empty.
'''
if not self.isEmpty():
return self.queue
print('Queue is empty. Nothing to peek in the queue.')
def delete(self):
'''
Deletes the stack
'''
self.queue = None
print('Queue deleted successfully.')
# Create a new queue with length = 5
q = Queue(length = 5)
# dequeue an item from the queue
print(q.dequeue())
# Check if the queue is empty
print(q.isEmpty())
# Peek item from the front of the queue
print(q.peek())
# Enqueue 3 items to the queue
q.enqueue(30)
q.enqueue(40)
q.enqueue(55)
# Check the size of the queue
print(q.size())
# Enqueue two more elements to the queue
q.enqueue(60)
q.enqueue(85)
# Peek in the front of the queue and print the response
print(q.peek())
# Equeue one more item to the queue
q.enqueue(100)
# Check if the queue is full
print(q.isFull())
# Enqueue an item from the queue
print(q.dequeue())
# Delete the queue
q.delete() ```

The output of the program is –

```Queue is empty. Nothing to dequeue.
None
True
Queue is empty. Nothing to peek in the queue.
None
Successfully added 30 to the queue.
Successfully added 40 to the queue.
Successfully added 55 to the queue.
3
Successfully added 60 to the queue.
Successfully added 85 to the queue.
30
Queue is full. New element cannot be placed in the queue.
True
Successfully removed element from front of the queue.
30
Queue deleted successfully.```

An anagram is a word or phrase that is created by rearranging the letters of another word or phrase, usually utilizing every letter exactly once. Examples include rearranging the words care to become race, binary to become brainy, and heart to become earth. To prove whether two strings are anagrams or not, we can perform sorting on both strings and if the sorted strings match each other then we can consider the strings to be anagrams of each other. The pseudocode can be given as –

1. Step 1: INITIALIZE both strings.
2. Step 2: INITIALIZE an anagram flag to be true.
3. Step 3: CHECK if both strings have the same length. If NO, then skip the steps and set the anagram flag to false.
4. Step 4: SORT the first string.
5. Step 5: SORT the second string.
6. Step 6: ITERATE through the string to perform the character-by-character comparison. If any one character is found to be not matching then set the flag to false and break the loop.
7. Step 7: DECLARE the strings as anagrams based on the flag value. If the flag is true then the strings are anagrams else not.

The python program for this is given as –

```string_1 = 'care'
string_2 = 'race'
len_str1 = len(string_1)
len_str2 = len(string_2)
anagram_flag = True
if len_str1 != len_str2:
anagram_flag = False
else:
string_1 = ''.join(sorted(string_1))
string_2 = ''.join(sorted(string_2))
for idx in range(0, len_str1):
if string_1[idx] != string_2[idx]:
anagram_flag = False
if anagram_flag:
print('The strings are anagrams')
else:
print('The strings are not anagrams') ```

In the case of the insertion sort algorithm, we divide the array into two parts: sorted array and unsorted array. Then from the unsorted array, we pick the first element and find its correct position in the sorted array. We repeat the process until there are no items left in the unsorted part of the array. The pseudocode for the insertion sort algorithm is –

1. Step 1: INITIALIZE an array.
2. Step 2: ITERATE through the index positions 1 to the end of the array.
3. Step 3: ASSIGN the key to the current index position. The elements at the left of this index position are part of the sorted array while the elements to the right are considered part of the unsorted array.
4. Step 4: CHECK if the element to the left of the current index is greater than the number. If true, then swap the positions. REPEAT this until we reach a value smaller than the current index or index position 0.

The python program for the insertion sort is –

```arr = [56, 63, 84, 90, 15, 38, 22, 5, 71, 49]
arr_length = len(arr)
for i in range(1, arr_length):
key = arr[i]
j = i - 1
while key < arr[j] and j >= 0:
arr[j+1] = arr[j]
j -= 1
arr[j+1] = key
print('Sorted array:', arr) ```

The output of the program is “Sorted array: [5, 15, 22, 38, 49, 56, 63, 71, 84, 90]”.

OOP stands for Object Oriented Programming. It is a way of writing code which involves classes, methods, attributes, and objects instead of traditional functions. Large, sophisticated, and actively updated or maintained programs are best fit for this method of development. The use of objects allows the creation of multiple unique instances of a class and the reuse of the methods and attributes of the class, thereby, improving code efficiency, reusability, and readability. The building blocks of OOP are –

• Classes – It is a user-defined data type which contains the attributes and methods.
• Objects – It is an instance of a class. Each object holds the data information uniquely within itself.
• Methods – It is a function written within a class. These functions can be accessed through the objects.
• Attributes – It is defined as property variables for a class. These can be accessed using the objects of the class. The value of the attributes might differ from object to object.

The main concepts of OOP include –

• Inheritance – Inheritance allows using the attributes and methods from the parent class within the child class. For example, a Vehicle class will have attributes such as top speed, mileage, manufacturing date, etc., and methods such as applying brakes, pressing the horn, etc. These attributes and methods apply to any kind of Vehicle; therefore, Bike and Car classes can inherit from the parent class, Vehicle, enabling them to use the defined attributes and methods in the Vehicle class.
• Abstraction – Abstraction helps to understand an underlying property of a class without exposing the internal details of the application. For example, if the Vehicle class is made as the abstraction class, then we can hide the logic behind apply brakes method. This will ensure that the user knows that this method will apply the brakes but does not learn about its internal working of it.
• Polymorphism – Polymorphism refers to having many forms. It can define various forms in which an object can be accessed.
• Encapsulation – Encapsulation adds security by avoiding exposing the information contained within an object to other objects. Therefore, an object’s data remains private and other objects cannot access this data.

Method overriding is an example of runtime polymorphism. Method overriding is implemented during inheritance that involves declaring the same method in the child class which can be found in the parent class. By doing this, we can use the method of the child class instead of the parent class whenever the object of the child class calls the method. Let us understand this with the help of an example.

```class Parent:
def foo(self):
print(‘Parent foo called’)
class Child1(Parent):
def foo(self):
print(‘Child1 foo called’)
class Child2(Parent):
pass
c1 = Child1()
c1.foo()
c2 = Child2()
c2.foo() ```

In the code, we have implemented three classes – one parent class and two child classes. In the parent class, we have a method named ‘foo’. Both the child classes – Child1 and Child2 inherit from the parent class. The Child1 class has its implementation of the ‘foo’ method. The Child2 class does not have its own ‘foo’ method. After we run the program, we will see that if the child class has its implementation of the parent class methods, then it will override it. Therefore, calling the ‘foo’ method using the Child1 class object will result in overriding the parent class method and calling the ‘foo’ method using the Child2 class object will call the parent class ‘foo’ method since it has not overridden the method. The output of the program is –

```Child1 foo called
Parent foo called ```

Time complexity refers to the time taken by a program to complete its execution. It is measured using the Big O notation. Big O notation is a language and a metric that is used to describe the efficiency of algorithms. Without understanding Big O notations, it is not possible to create efficient algorithms. If we don’t know when our algorithm gets faster or slower, we’ll struggle to judge our program performance. This concept gives us one way of describing how the time it takes to execute our program grows as the size of input grows. For example, a sorting algorithm might be quicker to sort a smaller array but as the size of the array increases, the time taken to sort the array using the same algorithm might increase drastically. In such cases, other sorting algorithms might turn out to be useful.

Time is not the only thing that matters in an algorithm. We might also care about the amount of memory or the space that is being consumed by the algorithm or the program. It is a parallel concept to time complexity. Space complexity is the measure of the amount of working storage that a program needs. As with time complexity, here we are concerned with how the space that is needed grows as the size of the input grows. For example, a smaller array will consume a lesser space than compared to a larger array. If you are using too many variables to store intermediate computations in your program then you might end up consuming more space.

Fibonacci sequence is the sequence of whole numbers 0,1, 1, 2, 3, 5, 8, ... which starts with 0 and 1, and where every number thereafter is equal to the sum of the previous two numbers.

The pseudocode for the program is –

• Step 1: CALL the fib function and pass the argument ‘n’.
• Step 2: CHECK if the number ‘n’ is less than 2. If true, return the number ‘n’.
• Step 3: RETURN the summation of CALL to fib function with ‘n-1’ and ‘n-2’ parameters respectively.

The python implementation for the same is –

```def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print('Fibonacci for n=8 is', fib(8)) ```

The output of the program is “Fibonacci for n=8 is 21”.

Inheritance is a way to form new classes using classes that have already been defined. Important benefits of inheritance are the ability to reuse code and make the program more readable. To further understand inheritance consider the following example:

class Vehicle:

```def __init__(self, mileage, no_of_wheels):
self.mileage = mileage
self.no_of_wheels = no_of_wheels
def apply_brakes(self):
print('Brakes applied.')
def press_horn(self):
print('Honkingggg!!!!!') ```

class Bike(Vehicle):

```def __init__(self, mileage):
super().__init__(mileage, no_of_wheels = 2)
# Creating an instance of a Bike class
bike_obj = Bike(mileage = 60)
# Accessing attributes instantiated in Parent class
print('Mileage:', bike_obj.mileage)
print('No of wheels:', bike_obj.no_of_wheels)
# Accessing methods instantiated in Parent class
bike_obj.apply_brakes()
bike_obj.press_horn() ```

The output of the program is –

```Mileage: 60
No of wheels: 2
Brakes applied.
Honkingggg!!!!! ```

In the python code, we have created a parent class, Vehicle, and a child class, Bike (inheriting from the parent class). The parent class, Vehicle, has two attributes, namely, ‘mileage’ and ‘no_of_wheels’. It also has two methods, namely, ‘apply_brakes()’ and ‘press_horn()’. In the child class, Bike, there are no attributes or methods defined but since we are inheriting the parent class, we can use all the methods and attributes of the parent class. We have created the attribute of the child class and accessed the above-mentioned attributes and methods as seen in the output.

A regular expression, or simply regex, allows us to look for general patterns in text data. For example, if we are looking for an email or phone number in a large document then we can define the pattern and extract all the available emails and phone numbers present in the document using regex. Regular expressions have a standardized set of rules for defining the pattern irrespective of the programming language. They are used widely and are an extremely powerful way to work with text data. Using some of these rules, we can define the phone pattern in regular expression as –

^[6-9]\d{9}\$

The ‘^’ marks at the beginning should be with the characters present in the square bracket where 6-9 means any number out of 6, 7, 8, and 9. These four numbers should be present in just one. Following this ‘\d’ means any digit and ‘{9}’ means repeated exactly 9 times. Therefore, the complete pattern describes that the matching string should start with a number 6, 7, 8, or 9 followed by 9 other digits, totalling 10 digits of a phone number.

Tree data structures are a form of non-linear data structure. With an increase in the number of data points, linear data structures are found to be more time-consuming. To avoid this time complexity, tree data structures can play a role. These are tree-like structures formed using nodes, roots, and edges. Since it is a non-linear data structure type, it has a multi-level hierarchy as shown below – • Node is an entity which contains a value along with the reference to its child nodes (Node 1-9 in the figure).
• Root is the topmost node in a tree (Node 1 in the figure).
• Leaf is the deepest node which does not have any further child nodes (Node 4, 5 6, 7, 8, 9 in the figure).
• Edge is the link or relationship between two nodes.
• Depth of a node defines the number of edges from the root node to the node (The depth of node 9 and node 7 are 3 and 2 respectively).
• Height of a node is the number of edges from the node to the leaf node (The height of nodes 9 and 3 are 0 and 1 respectively).

In essence, a binary search tree is just a binary tree with extra features. The first characteristic is that the value of the node in the left subtree is lower than or equal to the value of its parent node. The value of the node in the right subtree exceeds the value of its parent node. Here is an illustration of a binary tree. The root node of the example binary tree is node 56. For the first property, we stated that the value of the node in the left subtree is less than or equal to the root node. You can see that in this instance, 49 is less than 56. Now, we should have a node in the right subtree that is higher than the value of the root node. You can see that 63 is greater than 56 in this situation. We can observe that this attribute follows the same pattern down to the leaf node if we continue to assess it farther into the tree.

There is no index of the data elements stored in the binary search tree. As a substitute, it uses an implicit structure to keep track of each element's location. The addition and deletion of nodes may be accomplished fast due to this structure. In contrast to how we operate with arrays, where we must progressively tour each element until the correct one is located, in this case, we only need to walk the half tree. Next, we go on to the other tree's half. This produces the desired effect considerably more quickly than a straight loop would. Because a binary search tree is quicker than a binary tree, we could need one while sorting data.

The binary search algorithm searches the required element in the array by dividing the array into two parts. The algorithm can only be applied to an array which is already sorted. It can be implemented using two different approaches, namely, the iterative method and the recursive method. The underlying algorithm remains the same in both methods which work on the principle of ‘divide and conquer’. The iterative method has a complexity of O(1) whereas the recursive method has a complexity of O(log n) which makes the iterative method more efficient.

The pseudocode for implementing a binary search algorithm is –

• Step 1: INITIALIZE the array.
• Step 2: INITIALIZE the number whose index position needs to be found, say x.
• Step 3: DECLARE two pointers equal to index position 0 (say start) and last index (say end) in the array.
• Step 4: EVALUATE the central index position in the array.
• Step 5: CHECK if x is equal to the element at the central position. If true then return the index position and stop.
• Step 6: CHECK if x is greater than the number at the central index it means that x is present at the right half of the array. Shift the start index to the central index position + 1.
• Step 7: CHECK if x is smaller than the number at the central index it means that x is present at the left half of the array. Shift the end index to the central index position.
• Step 8: REPEAT steps 4 to 7 until x is found in the array.

The python implementation for the same is –

```# Initialize the array
arr = [5, 15, 22, 38, 49, 56, 63, 71, 84, 90]
# Define the search element
x = 22
# Calculate the length of the array
arr_length = len(arr)
# Assign start and end index positions
start = 0
end = arr_length - 1
while start <= end:
# Compute the middle index position
mid = start + (end - start)//2
# Check if the element is in the middle position
# Else reassign new start and end index positions
if arr[mid] == x:
idx = mid
break
elif arr[mid] < x:
start = mid + 1
else:
end = mid - 1
print(f"Index position for element {x} is", idx) ```

The output of the program is “Index position for element 22 is 2”.

The flowchart to find the smallest number in an integer array can be given as – The python implementation for the same is –

```# Initialize the array
arr = [56, 63, 84, 90, 15, 38, 22, 5, 71, 49]
# Calculate the length of the array
N = len(arr)
i = 0
# Assign the random smallest number at the start of the index position
result = arr
while i < N:
# Check if the current element is smaller than the result
if arr[i] < result:
result = arr[i]
# Increment the current index position
i += 1
print("Smallest element in the array is", result) ```

The output of the program is “Smallest element in the array is 5”.

The flowchart to find the missing number in an integer array can be given as – ```# Initialize the array
arr = [1, 1, 2, 2, 4, 5, 8, 9]
# Sort the array
arr.sort()
# Calculate the length of the array
N = len(arr)
# Initialize a new array with length N and 0 elements
narr = *N
# Mark the indexes as 1 if the item is present
for i in range(0, N):
if i + 1 in arr:
narr[i] = 1
print('The missing elements are:')
# Print the indexes where the element is still 0
for i in range(0, N):
if narr[i] == 0:
print(i + 1) ```

The output of the program is –

```The missing elements are:
3
6
7 ```

Multiplication of two matrices is only possible if the number of columns of the first matrix matches the number of rows of the second matrix. That means we can multiply the i x j matrix with j x k. The pseudocode for multiplying two matrices is given as (assuming we are multiplying i x j matrix with j x k) –

• Step 1: ASSIGN both the matrices (say A and B)
• Step 2: DECLARE i, j, k
• Step 3: INITIALIZE a zero matrix ‘result’ with i rows and k columns
• Step 4: FOR x = 0 to x = i – 1
• Step 5: FOR y = 0 to y = k – 1
• Step 6: FOR z = 0 to z = j – 1
• Step 7: ASSIGN result[x][z] = result[x][z] + A[x][z] * B[y][z]

The implementation in python language for the same is –

```# Initialize matrix A
A = [
[22, 18, 5],
[9, 15, 31],
[12, 14, 25],
]
# Initialize matrix B
B = [
[16, 8],
[3, 0],
[9, 11],
]
# Initialize i, j, k
i = len(A)
j = len(A)
k = len(B)
# Initialize resultant matrix
result = [[0,0], [0,0], [0,0]]
for x in range(0, i):
for y in range(0, k):
for z in range(0, j):
result[x][y] += A[x][z] * B[z][y]
for row in result:
print(row) ```

The output of the program is –

```[451, 231]
[468, 413]
[459, 371] ```

To swap two integer variables, we can use the addition (+) and subtraction (-) operators between the variables. Consider the two integer variables are x and y then we can swap them using –

```x = x + y
y = x – y
x = x - y ```

In this case, we first added the two integers x and y, and then stored them in x. We then assign x – y to y but x here is equal to x + y which means that we are assigning y = x – y = (x + y) – y = x. Next, we assign x as x – y where we are performing x = x – y = (x + y) – (x) = y. Therefore, by using some mathematical calculations we can swap two integer variables without using a temporary variable.

The merge sort algorithm is a ‘divide and conquer’ algorithm. In the "divide and conquer algorithm," a large problem is divided into smaller chunks, and when those chunks are so small that more division is impossible, we start merging them to find the solution. The input array is split in half and then repeatedly halved until no further division is possible. We begin merging them with sort order once the halving is complete. Finally, we reach the final answer in which we sort all elements. For example, let us consider the array [56, 63, 84, 90, 15, 38, 22, 5, 71, 49]. The split can be performed as – After splitting the array in half, we divided the two resulting chunks in half once more to create four chunks. We continued splitting these chunks until we ran out of methods to do so. The next step is to merge these chunks (starting from the bottom) which are nothing but arrays consisting of a single item. We'll make sure that each split array is now ordered during merging. The items were placed differently from the prior merge, as indicated by the orange places. Only the components with values 22 and 38 were shuffled during the initial merge. Three of the four arrays underwent shuffling during the second merge. During the third merge, one of the two arrays underwent shuffling. The sorted array is created by the last merge.

Sorting algorithms are divided into two categories based on the space they use and the stability of the algorithms. Based on stability, algorithms can further be classified into stable or unstable.

Stable sorting is the term for a sorting algorithm that does not alter the order in which related pieces of content appear after the content has been sorted. Consider an array with the repeating element "22," where the first instance is stored at memory address "x0001" and the second instance is placed at location "x0002" in the memory. The element "22" will preserve this order in stable sorting, meaning that the first instance of 22 in the sorted array is the one that occupied location "x0001," and the second instance is at position "x0002." In this case, memory is only being taken into account to discriminate between these two items that share the same value.

On the other hand, a sorting algorithm is said to be unstable if, after sorting the content, it changes the order in which related content appears. Therefore, if we use the same array, sorting will place the element "22" at position "x0002" ahead of the similar element at position "x0001" in the sequence. The algorithms can be classified into –

• Simple recursive algorithms – It functions similarly to iterative algorithms, but in this case, the recursion mimics a loop; that is, the algorithm repeatedly invokes itself.
• Dynamic algorithms – They employ memorization, which implies that they keep track of previous outcomes and use them to generate future outcomes. These algorithms are typically employed for optimisation problems. The objective is to select the best option from a variety of options. For instance, determining the fastest route under specific circumstances.
• Greedy algorithms – To discover the optimal answer to optimization issues, these algorithms are also used. It operates in stages. We pick the best available at each stage without considering the repercussions in the future (thus the term "greedy"), and we anticipate that by selecting a locally optimal solution at each stage, we will arrive at a globally optimal solution.
• Divide and conquer algorithms – There are two parts to the divide and conquer algorithm. The problem is broken down into smaller, related subproblems in the first section, and these are then solved recursively. The second component is that it incorporates the answers to the subproblems into the answer to the main problem. If an algorithm has at least two recursive calls, it is typically referred to as divide and conquer. Using the divide and conquer method, we can discover certain sorting algorithms.
• Brute force algorithms – This method merely tests every possibility until a workable solution is discovered. Identifying the password combination, for instance.
• Randomized algorithms – At least once throughout the tournament, these methods use a random number to choose the winner.

We need to first check if the lines are parallel or not. If they are parallel then there is no point of intersection. If they are not parallel, we can find their intersection points. The pseudocode for the program is given by –

• Step 1: ASSIGN the coordination for both the lines
• Step 2: GENERATE the line equation for the first line
• Step 3: GENERATE the line equation for the second line
• Step 4: CALCULATE the determinant value
• Step 5: CHECK IF the determinant is equal to 0. If yes, then DISPLAY that the lines are parallel and exit.
• Step 6: CALCULATE x and y which are the points of intersection.

The implementation in python language for the same is –

```# Assign coordinates for line AB and CD
A = (-5, -1)
B = (3, 3)
C = (1, 2)
D = (-2, -3)
# Generate the line equation for line AB
a1 = B - A # y2 - y1
b1 = A - B # x1 - x2
c1 = a1*A + b1*A
# Generate the line equation for line CD
a2 = D - C # y2 - y1
b2 = C - D # x1 - x2
c2 = a2*C + b2*C
# Calculate the determinant
det = a1 * b2 - a2 * b1
if det == 0: # Alternatively, check for a1/b1 == a2/b2
print('Lines AB and CD are parallel')
else:
# Calculate x
x = (b2 * c1 - b1 * c2) / det
# Calculate y
y = (a1 * c2 - a2 * c1) / det
print(f'Points AB and CD are intersecting at ({x}, {y})', ) ```

The output of the program is “Points AB and CD are intersecting at (1.0, 2.0).

We must comprehend the ideas of backtracking and recursion to put this programme into practice. Recursion plays a crucial role in backtracking. Backtracking is a general algorithm approach that takes into account looking through every potential combination to solve the computing problem and its type of recursion. A backtracking algorithm is a problem-solving algorithm that finds the desired result by applying a brute force method. The brute force method tests every potential solution before selecting the ideal one. But take note that it can often exclude a huge number of candidates with a single test, making it much faster than the brute force enumeration of all complete candidates. Backtracking is done when there are several solutions and we want all of them so we can eliminate several undesirable states in a single iteration.

Enumeration, optimization, and decision problems can all be solved through backtracking.

The implementation of the program to find all permutations of a string is a classic example of backtracking and can be implemented in python as –

```# Convert the array to a string
def arr_to_str(arr):
return ''.join(arr)
# Convert string to an array
def str_to_arr(string):
return list(string)
# Function to find all permutations of an array
def permute(arr, idx, length):
if idx == length:
print(arr_to_str(arr))
for i in range(idx, length):
# Performing swapping
temp = arr[idx]
arr[idx] = arr[i]
arr[i] = temp
# Recursively calling the function permute
permute(arr, idx + 1, length)
# Performing swapping (Backtracking)
temp = arr[idx]
arr[idx] = arr[i]
arr[i] = temp
string = "cat"
arr = str_to_arr(string)
arr_length = len(arr)
permute(arr, idx = 0, length =arr_length) ```

The output of the program is –

```cat
cta
act
atc
tac
tca ```

## Summary

The deciding aspect of any programming interview is always coding proficiency. Programmers are central to the success of a product or a solution that businesses build. As a successful programmer, you are expected to not just know how to code, but also understand the root of a problem. Having this perspective ensures that you’re coding and testing skills come in handy when you build the solution and find its shortcomings. The top 40 must do coding questions you would want to know are covered in this post so you can ace your interviews and land the job of your dreams. The questions include coding round questions for freshers as well as experienced professionals. We have covered theory questions, algorithms, pseudocodes, flowcharts, and even code blocks so that you do not miss out on your preparation journey. To know more, you can check out the Programming courses offered by Knowledgehut which helps you become a skilled programmer. They also have a dedicated C# Certification Course to learn the versatile language developed by Microsoft through immersive hands-on training, live sessions, real-life case studies, and much more. You need to keep updated with changes to ensure that your abilities remain useful given the nearly continual development and advancements in technology. The Coding classes by KnowledgeHut take care of this. With more than 400,000+ professionals trained by 650+ expert trainers in 100+ countries, it is the right choice to achieve high growth in your career and journey as a programmer or coder.