Category

Courses

- Agile Methodology
- Certified ScrumMaster (CSM) Certification
- Certified Scrum Product Owner (CSPO) Certification
- Leading SAFe 6.0 Certification
- Professional Scrum Master-Advanced™ (PSM-A) Training
- SAFe 6.0 Scrum Master (SSM) Certification
- Implementing SAFe 6.0 (SPC) Certification
- SAFe 6.0 Release Train Engineer (RTE) Certification
- SAFe 6.0 Product Owner Product Manager (POPM) Certification
- ICP-ACC Certification
- Agile Master's Program
- Agile Excellence Master's Program
- Kanban Management Professional (KMP I: Kanban System Design) Certification
- Professional Scrum Product Owner I (PSPO I) Training
- View All Courses

Accreditation Bodies

- Project Management
- Project Management Professional (PMP) Certification
- PRINCE2 Certification
- PRINCE2 Foundation Certification
- PRINCE2 Practitioner Certification
- Change Management Training
- Project Management Techniques Training
- Certified Associate in Project Management (CAPM) Certification
- Program Management Professional (PgMP) Certification
- Portfolio Management Professional (PfMP) Certification
- Oracle Primavera P6 Certification
- Project Management Master's Program
- Microsoft Project Training
- View All Courses

Accreditation Bodies

- Data Science
- Data Science Bootcamp
- Data Engineer Bootcamp
- Data Analyst Bootcamp
- AI Engineer Bootcamp
- Data Science with Python Certification
- Python for Data Science
- Machine Learning with Python
- Data Science with R
- Machine Learning with R
- Deep Learning Certification Training
- Natural Language Processing (NLP)
- View All Courses

- DevOps
Accreditation Bodies

- Cloud Computing
- AWS Certified Solutions Architect - Associate
- Multi-Cloud Engineer Bootcamp
- AWS Cloud Practitioner Certification
- Developing on AWS
- AWS DevOps Certification
- Azure Solution Architect Certification
- Azure Fundamentals Certification
- Azure Administrator Certification
- Azure Data Engineer Certification
- Azure Devops Certification
- AWS Cloud Architect Master's Program
- AWS Certified SysOps Administrator Certification
- Azure Security Engineer Certification
- Azure AI Solution Certification Training
- View All Courses

Career TrackSupercharge your career with our Multi-Cloud Engineer Bootcamp

KNOW MORE - Web Development
- Full-Stack Developer Bootcamp
- UI/UX Design Bootcamp
- Full-Stack [Java Stack] Bootcamp
- Software Engineer Bootcamp
- Software Engineer Bootcamp (with PMI)
- Front-End Development Bootcamp
- Back-End Development Bootcamp
- React Training
- Node JS Training
- Angular Training (Version 12)
- Javascript Training
- PHP and MySQL Training
- View All Courses

- IT Service Management
- ITIL 4 Foundation Certification
- ITIL Practitioner Certification
- ISO 14001 Foundation Certification
- ISO 20000 Certification
- ISO 27000 Foundation Certification
- ITIL 4 Specialist: Create, Deliver and Support Training
- ITIL 4 Specialist: Drive Stakeholder Value Training
- ITIL 4 Strategist Direct, Plan and Improve Training
- View All Courses

- Programming
- BI And Visualization
- Blockchain
- Big Data
- Mobile App Development
- Software Testing
- Selenium Certification Training
- ISTQB Foundation Certification
- ISTQB Advanced Level Security Tester Training
- ISTQB Advanced Level Test Manager Certification
- ISTQB Advanced Level Test Analyst Certification
- ISTQB Advanced Level Technical Test Analyst Certification
- Silk Test Workbench Training
- Automation Testing using TestComplete Training
- Cucumber Training
- Functional Testing Using Ranorex Training
- Teradata Certification Training
- View All Courses

- Business Management
- Quality Management
- IT Security
- Cyber Security Bootcamp
- Certified Ethical Hacker (CEH v12) Certification
- Certified Information Systems Auditor (CISA) Certification
- Certified Information Security Manager (CISM) Certification
- Certified Information Systems Security Professional (CISSP) Certification
- Cybersecurity Master's Program
- Certified Cloud Security Professional (CCSP) Certification
- Certified Information Privacy Professional - Europe (CIPP-E) Certification
- Control Objectives for Information and Related Technology (COBIT5) Foundation
- Payment Card Industry Security Standards (PCI-DSS) Certification
- Introduction to Forensic

- Digital Marketing
- Risk Management
- Finance
- Credit Risk Management
- Budget Analysis and Forecasting
- International Financial Reporting Standards (IFRS) for SMEs
- Diploma In International Financial Reporting
- Certificate in International Financial Reporting
- Corporate Governance
- Finance for Non-Finance Managers
- Financial Modeling with Excel
- Auditing and Assurance

- Database
- Soft Skills Training
- CompTIA
- Master of Business Administration
- Other
- MS Excel 2010
- Advanced Excel 2013
- IoT
- Certified Supply Chain Professional
- Software Estimation and Measurement Using IFPUG FPA
- Software Size Estimation and Measurement using IFPUG FPA & SNAP
- Leading and Delivering World Class Product Development Course
- Product Management and Product Marketing for Telecoms IT and Software
- Foundation Certificate in Marketing
- Flow Measurement and Custody Transfer Training Course
- View All Courses

- Home
- Programming
- Coding Interview Questions and Answers for 2024

- 4.7 Rating
- 50 Question(s)
- 25 Mins of Read
- 7220 Reader(s)

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)
- 25 Mins of Read
- 7220 Reader(s)

Filter By

Clear all

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:

**Arrays**: It is one of the simplest forms of data structure which stores a series of items in a sequential manner.**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.**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.**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.**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.

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.

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[0] # 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 = “radar” 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 = 'assemblylanguage' 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**”.

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 –

- Step 1: ASSIGN two pointers at the start and end of the array.
- Step 2: SWAP the two values represented by the two assigned pointers.
- Step 3: Increment the first (start) pointer by 1 and decrement the second (end) pointer by 1.
- 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.

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 –

- Step 1: INITIALIZE an array with integer elements.
- 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)
- 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)
- 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.
- 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[0] 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 –

- Step 1: INITIALIZE both strings.
- Step 2: INITIALIZE an anagram flag to be true.
- Step 3: CHECK if both strings have the same length. If NO, then skip the steps and set the anagram flag to false.
- Step 4: SORT the first string.
- Step 5: SORT the second string.
- 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.
- 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 –

- Step 1: INITIALIZE an array.
- Step 2: ITERATE through the index positions 1 to the end of the array.
- 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.
- 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[0] 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 = [0]*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[0]) k = len(B[0]) # 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[1] - A[1] # y2 - y1 b1 = A[0] - B[0] # x1 - x2 c1 = a1*A[0] + b1*A[1] # Generate the line equation for line CD a2 = D[1] - C[1] # y2 - y1 b2 = C[0] - D[0] # x1 - x2 c2 = a2*C[0] + b2*C[1] # 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

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:

**Arrays**: It is one of the simplest forms of data structure which stores a series of items in a sequential manner.**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.**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.**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.**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.

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.

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[0] # 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 = “radar” 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 = 'assemblylanguage' 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**”.

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 –

- Step 1: ASSIGN two pointers at the start and end of the array.
- Step 2: SWAP the two values represented by the two assigned pointers.
- Step 3: Increment the first (start) pointer by 1 and decrement the second (end) pointer by 1.
- 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.

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 –

- Step 1: INITIALIZE an array with integer elements.
- 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)
- 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)
- 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.
- 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[0] 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 –

- Step 1: INITIALIZE both strings.
- Step 2: INITIALIZE an anagram flag to be true.
- Step 3: CHECK if both strings have the same length. If NO, then skip the steps and set the anagram flag to false.
- Step 4: SORT the first string.
- Step 5: SORT the second string.
- 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.
- 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 –

- Step 1: INITIALIZE an array.
- Step 2: ITERATE through the index positions 1 to the end of the array.
- 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.
- 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[0] 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 = [0]*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[0]) k = len(B[0]) # 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[1] - A[1] # y2 - y1 b1 = A[0] - B[0] # x1 - x2 c1 = a1*A[0] + b1*A[1] # Generate the line equation for line CD a2 = D[1] - C[1] # y2 - y1 b2 = C[0] - D[0] # x1 - x2 c2 = a2*C[0] + b2*C[1] # 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

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.

Submitted questions and answers are subjecct to review and editing,and may or may not be selected for posting, at the sole discretion of Knowledgehut.

Get a 1:1 Mentorship call with our Career Advisor

- Get Job-Ready Digital Skills
- Experience Outcome-Based Immersive Learning
- Get Trained by a Stellar Pool of Industry Experts
- Best-In-Class Industry-Vetted Curriculum

By tapping submit, you agree to KnowledgeHut Privacy Policy and Terms & Conditions