Michael Lubinsky

Personal Page

View the Project on GitHub

https://python.plainenglish.io/not-another-python-interview-guide-top-501-problems-to-solve-part-1-24441d435932

https://python.plainenglish.io/101-advanced-everyday-python-for-data-scientists-669c9b417707

https://python.plainenglish.io/101-advanced-everyday-python-for-data-scientists-669c9b417707

https://python.plainenglish.io/a-comprehensive-guide-to-python-automation-streamlining-tasks-and-boosting-productivity-fad00c5b62c5

https://python.plainenglish.io/a-comprehensive-guide-to-python-automation-streamlining-tasks-and-boosting-productivity-fad00c5b62c5

https://python.plainenglish.io/

Now lets start with #1–100 of 501

1) Write a Python function to check whether a given number is prime or not.

def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True

# Example usage:
print(is_prime(17))  # Output: True
print(is_prime(4))   # Output: False

Explanation: This function checks if a number is prime by attempting to divide it by all numbers up to its square root. If any divisor is found, it returns False; otherwise, it returns True.

2) Write a Python function to find the largest continuous sum in a given list of integers.

def max_subarray_sum(arr):
    max_sum = current_sum = arr[0]
    for num in arr[1:]:
        current_sum = max(num, current_sum + num)
        max_sum = max(max_sum, current_sum)
    return max_sum

# Example usage:
print(max_subarray_sum([-2, -3, 4, -1, -2, 1, 5, -3]))  # Output: 7

Explanation:
This function uses Kadanes algorithm to find the maximum sum of a contiguous subarray.
It iterates through the list, updating the current sum and maximum sum as needed.

3) What is the difference erence between ‘is’ and ‘==’ inPython?

'==' checks for equality, meaning it checks whether the values of two variables are the same.
'is' checks for identity, meaning it checks whether two variables point to the same object in memory.
 
# 'is' checks for identity, '==' checks for equality

a = [1, 2, 3]
b = a
c = list(a)
print(a == b)  # Output: True
print(a is b)  # Output: True
print(a == c)  # Output: True
print(a is c)  # Output: False

4) What is the purpose of the ‘enumerate’ function in Python? Provide an example.

fruits = ['apple', 'banana', 'cherry']
for index, fruit in enumerate(fruits):
    print(index, fruit)

# Output:
# 0 apple
# 1 banana
# 2 cherry

Explanation:
enumerate provides a convenient way to access both the index and the value of items in a list,
making it useful for loops where you need both.

5) What is the purpose of the ‘zip’ function in Python? Provide an example.

names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
for name, age in zip(names, ages):
    print(f"{name} is {age} years old")

# Output:
# Alice is 25 years old
# Bob is 30 years old
# Charlie is 35 years old

Explanation:
zip combines elements from multiple lists into a single iterable of tuples,
pairing elements based on their position.

6) What is the purpose of the ‘yield’ keyword in Python? Provide an example.

def count_down(num):
    while num > 0:
        yield num
        num -= 1

# Example usage:
for number in count_down(3):
    print(number)

# Output:
# 3
# 2
# 1
Explanation:
yield allows a function to return values one at a time as they are needed,
creating a generator that can be iterated over.

7) What is the difference between a list comprehension and a generator expression in Python?

List Comprehension Example:

squares = [x**2 for x in range(10)]
print(squares)
# Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Generator Expression Example:

squares_gen = (x**2 for x in range(10))
print(list(squares_gen))
# Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Explanation:
 List comprehensions generate lists, while generator expressions create generators.
 Generators are more memory-efficient as they yield items one at a time.

8) Write a Python function to check whether a given string is a palindrome or not.


def is_palindrome(s):
    return s == s[::-1]

# Example usage:
print(is_palindrome("radar"))  # Output: True
print(is_palindrome("hello"))  # Output: False

Explanation: This function checks if a string is the same forwards and backwards, which defines a palindrome.

9) Write a Python function to find the second highest number in a list.

def second_highest(lst):
    unique_sorted = sorted(set(lst), reverse=True)
    return unique_sorted[1] if len(unique_sorted) > 1 else None

# Example usage:
print(second_highest([1, 2, 3, 4, 5]))  # Output: 4
print(second_highest([5, 5, 5, 5]))     # Output: None

Explanation:
This function removes duplicates with set, sorts the list, and returns the second highest number if it exists.

10) Write a Python function to count the number of vowels in a given string.

def count_vowels(s):
    return sum(1 for char in s if char.lower() in 'aeiou')

# Example usage:
print(count_vowels("hello world"))  # Output: 3

Explanation: This function counts vowels in a string using a generator expression,
checking each character against a set of vowels.

11) Write a Python function to find the common elements between two lists.

def find_common_elements(list1, list2):
    return list(set(list1) & set(list2))

# Example usage:
print(find_common_elements([1, 2, 3, 4], [3, 4, 5, 6]))  # Output: [3, 4]

Explanation:
This function uses set intersection to find common elements between two lists, which is efficient and concise.

12) Write a Python function to reverse a linked list.

class ListNode:
    def __init__(self, value=0, next=None):
        self.value = value
        self.next = next

def reverse_linked_list(head):
    previous = None
    current = head
    while current:
        next_node = current.next
        current.next = previous
        previous = current
        current = next_node
    return previous

# Example usage:
# Creating a linked list 1->2->3->None
head = ListNode(1, ListNode(2, ListNode(3)))
reversed_head = reverse_linked_list(head)
while reversed_head:
    print(reversed_head.value, end=" ")
    reversed_head = reversed_head.next  # Output: 3 2 1

Explanation: This function reverses a singly linked list by changing the direction of the links between nodes.

13) Write a Python function to find the shortest path between two nodes in a graph.

import heapq

def shortest_path(graph, start, end):
    min_heap = [(0, start)]
    visited = set()
    distances = {node: float('inf') for node in graph}
    distances[start] = 0

    while min_heap:
        current_distance, current_node = heapq.heappop(min_heap)
        if current_node in visited:
            continue
        visited.add(current_node)

        if current_node == end:
            return current_distance

        for neighbor, weight in graph[current_node]:
            distance = current_distance + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(min_heap, (distance, neighbor))

    return float('inf')

# Example usage:
graph = {
    'A': [('B', 1), ('C', 4)],
    'B': [('C', 1), ('D', 2)],
    'C': [('D', 1)],
    'D': []
}
print(shortest_path(graph, 'A', 'D'))  # Output: 4

Explanation:
This function implements Dijkstras algorithm using a priority queue to find the shortest path in a weighted graph.

14) Write a Python function to find the intersection of two sorted lists.

def intersection_of_sorted_lists(list1, list2):
    i, j = 0, 0
    intersection = []
    while i < len(list1) and j < len(list2):
        if list1[i] < list2[j]:
            i += 1
        elif list1[i] > list2[j]:
            j += 1
        else:
            intersection.append(list1[i])
            i += 1
            j += 1
    return intersection

# Example usage:
print(intersection_of_sorted_lists([1, 2, 4, 5, 6], [2, 3, 5, 7]))  # Output: [2, 5]

Explanation:
This function finds the intersection of two sorted lists by using two pointers, efficiently comparing elements.

15) Write a Python function to fi nd the longest common prefix among a list of strings.

def longest_common_prefix(strs):
    if not strs:
        return ""
    shortest = min(strs, key=len)
    for i, char in enumerate(shortest):
        for other in strs:
            if other[i] != char:
                return shortest[:i]
    return shortest

# Example usage:
print(longest_common_prefix(["flower", "flow", "flight"]))  # Output: "fl"

Explanation:
This function finds the longest common prefix by comparing characters of the shortest string with all other strings.

16) Write a Python function to perform a binary search on a sorted list.

def binary_search(arr, target):
    low, high = 0, len(arr) - 1
    while low <= high:
        mid = (low + high) // 2
        if arr[mid] < target:
            low = mid + 1
        elif arr[mid] > target:
            high = mid - 1
        else:
            return mid
    return -1

# Example usage:
print(binary_search([1, 2, 3, 4, 5, 6], 4))  # Output: 3

Explanation:
This function performs a binary search to find the index of a target value within a sorted array,
returning -1 if the target is not found.

17) Write a Python function to find the maximum sum of a contiguous subarray with a size of k in a given list of integers.

def max_sum_subarray_k(arr, k):
    max_sum = sum(arr[:k])
    current_sum = max_sum
    for i in range(k, len(arr)):
        current_sum += arr[i] - arr[i - k]
        max_sum = max(max_sum, current_sum)
    return max_sum

# Example usage:
print(max_sum_subarray_k([1, 2, 3, 4, 5, 6], 3))  # Output: 15

Explanation:
This function calculates the maximum sum of any contiguous subarray of size k using a sliding window approach.

18) Write a Python function to implement a stack using a linked list.

class StackNode:
    def __init__(self, value):
        self.value = value
        self.next = None

class Stack:
    def __init__(self):
        self.top = None

    def push(self, value):
        new_node = StackNode(value)
        new_node.next = self.top
        self.top = new_node

    def pop(self):
        if self.top is None:
            return None
        popped_value = self.top.value
        self.top = self.top.next
        return popped_value

# Example usage:
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print(stack.pop())  # Output: 3
print(stack.pop())  # Output: 2

Explanation:
This function implements a stack using a linked list where each node contains a value and a reference to the next node.

19) Write a Python function to implement a queue using two stacks.

class Queue:
    def __init__(self):
        self.in_stack = []
        self.out_stack = []

    def enqueue(self, item):
        self.in_stack.append(item)

    def dequeue(self):
        if not self.out_stack:
            while self.in_stack:
                self.out_stack.append(self.in_stack.pop())
        return self.out_stack.pop() if self.out_stack else None

# Example usage:
queue = Queue()
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
print(queue.dequeue())  # Output: 1
print(queue.dequeue())  # Output: 2

Explanation:
This function implements a queue using two stacks. One stack is used for enqueuing, and the other for dequeuing.

20) Write a Python function to find the longest increasing subsequence in a given list of integers.

def longest_increasing_subsequence(nums):
    if not nums:
        return 0
    dp = [1] * len(nums)
    for i in range(1, len(nums)):
        for j in range(i):
            if nums[i] > nums[j]:
                dp[i] = max(dp[i], dp[j] + 1)
    return max(dp)

# Example usage:
print(longest_increasing_subsequence([10, 9, 2, 5, 3, 7, 101, 18]))  # Output: 4

Explanation:
This function uses dynamic programming to find the length of the longest increasing subsequence in a list of integers.
 Each element in the dp array keeps track of the longest subsequence ending at that index.

21) Write a Python function to find the shortest path between two nodes in a graph using Dijkstra’s algorithm.

import heapq

def dijkstra_algorithm(graph, start_node):
    distances = {node: float('inf') for node in graph}
    distances[start_node] = 0
    priority_queue = [(0, start_node)]
    
    while priority_queue:
        current_distance, current_node = heapq.heappop(priority_queue)
        
        if current_distance > distances[current_node]:
            continue
        
        for neighbor, weight in graph[current_node].items():
            distance = current_distance + weight
            
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(priority_queue, (distance, neighbor))
    
    return distances

# Example usage:
graph = {
    'A': {'B': 1, 'C': 4},
    'B': {'C': 1, 'D': 2},
    'C': {'D': 1},
    'D': {}
}
print(dijkstra_algorithm(graph, 'A'))  # Output: {'A': 0, 'B': 1, 'C': 2, 'D': 3}

Explanation:
 This function implements Dijkstras algorithm to find the shortest path from a start node to all other nodes in a weighted graph.
 It uses a priority queue to always process the nearest available node.

22) Write a Python function to find the longest common substring between two given strings.

def longest_common_substring(str1, str2):
    m, n = len(str1), len(str2)
    max_len = 0
    ending_index = 0
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if str1[i - 1] == str2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
                if dp[i][j] > max_len:
                    max_len = dp[i][j]
                    ending_index = i
            else:
                dp[i][j] = 0
    
    return str1[ending_index - max_len: ending_index]

# Example usage:
print(longest_common_substring("abcde", "abfce"))  # Output: "ab"

Explanation:
This function uses dynamic programming to find the longest common substring between two strings.
 It maintains a table dp where dp[i][j] is the length of the longest common substring ending at str1[i-1] and str2[j-1].

23) Write a Python function to check if a given string is a palindrome.

def is_palindrome(s):
    return s == s[::-1]

# Example usage:
print(is_palindrome("radar"))  # Output: True
print(is_palindrome("hello"))  # Output: False

Explanation:
This function checks if a string is the same forwards and backwards, which defines a palindrome.

24) Write a Python function to sort a given list of integers using the quicksort algorithm.

def quicksort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quicksort(left) + middle + quicksort(right)

# Example usage:
print(quicksort([3,6,8,10,1,2,1]))  # Output: [1, 1, 2, 3, 6, 8, 10]

Explanation: This function implements the quicksort algorithm, a divide-and-conquer sorting algorithm.

It selects a pivot and partitions the list into elements less than, equal to, and greater than the pivot,
and recursively sorts the partitions.

25) Write a Python function to generate all permutations of a given list of integers.

from itertools import permutations

def generate_permutations(lst):
    return list(permutations(lst))

# Example usage:
print(generate_permutations([1, 2, 3]))  # Output: [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

Explanation:
This function uses the permutations function from the itertools module to generate all possible permutations of the input list.

26) Write a Python function to merge two sorted arrays into a single sorted array.

def merge_sorted_arrays(arr1, arr2):
    result = []
    i, j = 0, 0
    while i < len(arr1) and j < len(arr2):
        if arr1[i] < arr2[j]:
            result.append(arr1[i])
            i += 1
        else:
            result.append(arr2[j])
            j += 1
    result.extend(arr1[i:])
    result.extend(arr2[j:])
    return result

# Example usage:
print(merge_sorted_arrays([1, 3, 5], [2, 4, 6]))  # Output: [1, 2, 3, 4, 5, 6]

Explanation:
This function merges two sorted arrays into a single sorted array by comparing elements from both arrays
and appending the smaller one to the result list.

27) Write a Python function to find the maximum subarray sum in a given array of integers.

def max_subarray_sum(arr):
    max_sum = current_sum = arr[0]
    for num in arr[1:]:
        current_sum = max(num, current_sum + num)
        max_sum = max(max_sum, current_sum)
    return max_sum

# Example usage:
print(max_subarray_sum([-2, -3, 4, -1, -2, 1, 5, -3]))  # Output: 7

Explanation:
This function uses Kadanes algorithm to find the maximum sum of a contiguous subarray within a one-dimensional array of numbers.

28) Write a Python function to find the first non￾repeating character in a given string.

def first_non_repeating_character(s):
    frequency = {}
    for char in s:
        if char in frequency:
            frequency[char] += 1
        else:
            frequency[char] = 1
    for char in s:
        if frequency[char] == 1:
            return char
    return None

# Example usage:
print(first_non_repeating_character("alphabet"))  # Output: 'l'

Explanation:
This function finds the first non-repeating character in a string by creating a frequency dictionary
 and then checking which character has a frequency of one.

29) Write a Python function to reverse a given linked list.

class ListNode:
    def __init__(self, value=0, next=None):
        self.value = value
        self.next = next

def reverse_linked_list(head):
    previous = None
    current = head
    while current:
        next_node = current.next
        current.next = previous
        previous = current
        current = next_node
    return previous

# Example usage:
# Creating a linked list 1->2->3->None
head = ListNode(1, ListNode(2, ListNode(3)))
reversed_head = reverse_linked_list(head)
while reversed_head:
    print(reversed_head.value, end=" ")  # Output: 3 2 1

Explanation: This function reverses a singly linked list by changing the direction of the links between nodes.

30) Write a Python function to implement binary search on a given sorted array of integers.

def binary_search(arr, target):
    low, high = 0, len(arr) - 1
    while low <= high:
        mid = (low + high) // 2
        if arr[mid] < target:
            low = mid + 1
        elif arr[mid] > target:
            high = mid - 1
        else:
            return mid
    return -1

# Example usage:
print(binary_search([1, 2, 3, 4, 5, 6], 4))  # Output: 3

Explanation:
This function performs a binary search to find the index of a target value within a sorted array,
returning -1 if the target is not found.

31) Write a Python function to implement the merge sort algorithm to sort a given list of integers.

def merge_sort(arr):
    if len(arr) > 1:
        mid = len(arr) // 2
        left = arr[:mid]
        right = arr[mid:]

        merge_sort(left)
        merge_sort(right)

        i = j = k = 0

        while i < len(left) and j < len(right):
            if left[i] < right[j]:
                arr[k] = left[i]
                i += 1
            else:
                arr[k] = right[j]
                j += 1
            k += 1

        while i < len(left):
            arr[k] = left[i]
            i += 1
            k += 1

        while j < len(right):
            arr[k] = right[j]
            j += 1
            k += 1

# Example usage:
arr = [12, 11, 13, 5, 6, 7]
merge_sort(arr)
print("Sorted array is:", arr)

Explanation:
 Merge sort is a divide and conquer algorithm that divides the input list into two halves,
calls itself for the two halves, and then merges the two sorted halves.
The merge_sort function recursively splits the list into halves until the sublists have only one element each.
Then, it merges those sorted sublists to produce the sorted answer.

32) Write a Python function to implement the quicksort algorithm to sort a given list of integers.

def quicksort(arr):
    if len(arr) <= 1:
        return arr
    else:
        pivot = arr[len(arr) // 2]
        left = [x for x in arr if x < pivot]
        middle = [x for x in arr if x == pivot]
        right = [x for x in arr if x > pivot]
        return quicksort(left) + middle + quicksort(right)

# Example usage:
arr = [3,6,8,10,1,2,1]
print(quicksort(arr))

Explanation:
Quicksort is a divide and conquer algorithm. It picks an element as pivot and partitions the given array around the picked pivot.
There are many different versions of quicksort that pick pivot in different ways.
This implementation uses the middle element as pivot.

33) Write a Python function to implement the breadth-first search algorithm to traverse a given tree.

from collections import deque

def bfs(root):
    if not root:
        return []
    queue = deque([root])
    result = []
    while queue:
        node = queue.popleft()
        result.append(node.value)
        if node.left:
            queue.append(node.left)
        if node.right:
            queue.append(node.right)
    return result

# Assuming a Node class with attributes 'value', 'left', and 'right'

# Example usage:
# root = Node(1, Node(2), Node(3))
# print(bfs(root))  # Output: [1, 2, 3]

Explanation:
Breadth-first search (BFS) is an algorithm for traversing or searching tree or graph data structures.
It starts at the tree root and explores the neighbor nodes at the present depth prior to moving on to nodes at the next depth level.

34) Write a Python function to implement the depth￾first search algorithm to traverse a given tree.

def dfs(node):
    if not node:
        return []
    return [node.value] + dfs(node.left) + dfs(node.right)

# Assuming a Node class with attributes 'value', 'left', and 'right'
# Example usage:
# root = Node(1, Node(2), Node(3))
# print(dfs(root))  # Output: [1, 2, 3]

Explanation:
Depth-first search (DFS) is an algorithm for traversing or searching tree or graph data structures.
The algorithm starts at the root node and explores as far as possible along each branch before backtracking.

35) What is the output of the following code?

a = [1, 2, 3]
b = a
a.append(4)
print(b)
Output: [1][2][3][4]

Explanation: Here, b is assigned the same list as a.
When a.append(4) is called, it modifies the list a refers to,
and since b refers to the same list, b also reflects this change.

36) What is the output of the following code?

a = "hello"
b = a
a += " world"
print(b)
Output: hello

Explanation: Strings in Python are immutable.
When a += " world" is executed, a new string is created and a is updated to refer to it,
but b still refers to the original string.

37) What is the output of the following code?

a = [1, 2, 3]
b = a[:]
a.append(4)
print(b)
Output: [1][2][3]

Explanation: b = a[:] creates a new list that is a copy of a, 
so when a is modified, b remains unchanged.

38) What is the output of the following code?

a = 5
b = 10
a, b = b, a
print(a, b)
Output: 10 5

Explanation: This is a Pythonic way to swap the values of a and b. 
After the swap, a becomes 10 and b becomes 5.

39) What is the output of the following code?

a = [1, 2, 3]
b = a.copy()
a.append(4)
print(b)
30 All rights reserved InterviewBible.com 2023
InterviewBible.com
Output: [1][2][3]

Explanation: b = a.copy() creates a shallow copy of a. 
Thus, when a is modified, b does not change.

40) What is the output of the following code?

a = [1, 2, 3]
b = a
a = [4, 5, 6]
print(b)
Output: [1][2][3]

Explanation: b is assigned to refer to the same list as a.
When a is assigned a new list [4][5][6], 
it does not affect b, which still refers to the original list.

41) What is the output of the following code?

a = "hello"
a[0] = "H"
print(a)
Output: This code will result in a TypeError.

Explanation: 
Strings in Python are immutable, which means you cannot change an existing string. 
The attempt to modify the string by assigning a new value to a will raise a TypeError.

42) What is the output of the following code?

a = [1, 2, 3]
b = [4, 5, 6]
a + b
print(a)
Output: [1][2][3]

Explanation: The a + b operation creates a new list but does not modify a. 
The print(a) statement outputs the original list a.

43) What is the output of the following code?

a = [1, 2, 3]
b = a
c = b
a.append(4)
print(c)
Output: [1,[2][3][4]

Explanation: Since b and c are references to the same list as a, appending 4 to a also affects b and c.
Thus, c shows the updated list.

44) What is the output of the following code?

a = {"apple": 3, "banana": 2, "orange": 1}
b = sorted(a)
print(b)
Output: ['apple', 'banana', 'orange']

Explanation:
The sorted() function, when used on a dictionary, returns a list of keys sorted alphabetically.

45) What is the output of the following code?

a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)
print(a is b)
Output:

True
False

Explanation: 
a == b checks for value equality and returns True because both lists have the same items in the same order.
a is b checks for identity (i.e., whether both variables point to the same object), 
which is False because a and b are different list objects.

46) What is the output of the following code?

a = "hello"
b = a
a = a.upper()
print(b)
Output: hello

Explanation:
Strings are immutable, so a.upper() creates a new string and assigns it to a, but b still points to the original string.

47) What is the output of the following code?

a = [1, 2, 3]
a *= 2
print(a)
Output: [1][2][3][1][2][3]

Explanation:
The *= 2 operation extends the list a by repeating its elements, effectively doubling the list.

48) What is the output of the following code?

a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)
print(a is b)
Output:

True
False
Explanation:
Similar to question 45, a == b returns True because the lists have the same elements in the same order, and a is b returns False because they are different objects.

49) What is the output of the following code?

a = {"apple": 3, "banana": 2, "orange": 1}
print(a["pear"])
Output: This code will result in a KeyError.

Explanation: The key "pear" does not exist in the dictionary a, so attempting to access it raises a KeyError.

50) What is the output of the following code?

a = "hello"
b = a
a += " world"
print(a is b)
Output: False

Explanation:
Initially, b is the same object as a.
However, when a is modified with +=, a new string is created and assigned to a.
Thus, a is no longer the same object as b, resulting in a is b being False.

51) What is the output of the following code?

a = [1, 2, 3]
b = a[:]
c = a
a.append(4)
print(b)
print(c)
Output:

[1, 2, 3]
[1, 2, 3, 4]

Explanation:
 b is a copy of a at the time of assignment, so changes to a do not affect b. c is a reference to the same list as a,
so changes to a also appear in c.

52) What is the output of the following code?

a = {"apple": 3, "banana": 2, "orange": 1}
print(sorted(a, key=lambda x: a[x]))
Output: ['orange', 'banana', 'apple']

Explanation:
The sorted() function is used with a key function that sorts the dictionary keys based on their corresponding values in ascending order.

75) Can you explain the difference between an abstract class and an interface in Python?

  In Python, an abstract class can have both abstract methods (which don’t have an implementation) and concrete methods (which do).
It is used when you want to create a base class that defines a blueprint for derived classes.
 An interface in Python, often achieved using abstract base classes,
strictly contains methods that have no implementation and must be implemented by derived classes.
Python does not have explicit support for interfaces like some other languages but achieves similar functionality through abstract base classes.

76) Can you explain how Python’s garbage collection works, and what are some strategies for managing memory usage?

  Python uses a form of automatic memory management known as garbage collection.
The primary mechanism is reference counting, where each object keeps track of how many references point to it.
When references to an object drop to zero, the memory occupied by the object is reclaimed.
Python also uses a generational garbage collector for cyclic references.
Strategies for managing memory include minimizing reference cycles, using del to remove references, and employing libraries like gc for manual garbage collection control.

77) Explain the Global Interpreter Lock (GIL) in Python and its implications for concurrency.

 The Global Interpreter Lock (GIL) is a mutex that protects access to Python objects,
preventing multiple native threads from executing Python bytecodes at once.
This lock is necessary because Python’s memory management is not thread-safe.
The GIL can be a bottleneck in CPU-bound and multi-threaded code,
as it allows only one thread to execute at a time even on multi-core processors.
 For true parallelism, Python developers often use multiprocessing or switch to implementations like Jython or IronPython, which don’t have a GIL.

78) What is the difference between deep and shallow copying in Python, and when would you use each?

 Shallow copying in Python creates a new object but inserts references into it to the objects found in the original.
Deep copying creates a new object and recursively adds copies of nested objects present in the original.
Shallow copy is faster and sufficient when the copied object does not contain nested objects that might be modified.
Deep copy is used when the new object needs to be fully independent of the original, including all nested objects.

79) How do you count the number of occurrences of an element in a list in Python?

a = [1, 2, 3, 2, 1, 5, 6, 2]
print(a.count(2))  # Output: 3

80) How do you remove all whitespace from a string in Python?

s = " a b c "
s = s.replace(" ", "")
print(s)  # Output: "abc"
Alternatively, using regular expressions:

import re
s = " a b c "
s = re.sub(r"\s+", "", s)
print(s)  # Output: "abc"

81) How do you get the current working directory in Python?

import os
current_directory = os.getcwd()
print("Current Working Directory:", current_directory)

You can obtain the current working directory in Python using the os.getcwd() method from the os module
 or the Path.cwd() method from the pathlib module.

82) How do you flatten a nested list in Python?


def flatten_list(nested_list):
    return [item for sublist in nested_list for item in sublist]

nested_list = [[1, 2, 3], [4, 5], [6]]
print("Flattened list:", flatten_list(nested_list))

To flatten a nested list in Python, you can use a list comprehension, the itertools.chain() method,
or a recursive approach.
A simple list comprehension for one level of nesting would look like:

[item for sublist in nested_list for item in sublist].

83) How do you check if a number is prime in Python?

def is_prime(n):
    if n <= 1:
        return False
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True

print(is_prime(11))  # Output: True
print(is_prime(4))   # Output: False

To check if a number is prime, you can iterate from 2 to the square root of the number
and check if the number is divisible by any of those values.
 If it is divisible, it is not prime; otherwise, it is prime.

84) How do you convert a string to a datetime object in Python?

from datetime import datetime

date_string = "01/01/2020"
date_object = datetime.strptime(date_string, "%d/%m/%Y")
print("Date Object:", date_object)

 You can convert a string to a datetime object using the datetime.strptime() method from the datetime module.
You need to specify the string and the format that matches the string.

85) How do you merge two dictionaries in Python?

dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}

merged_dict = {**dict1, **dict2}
print("Merged Dictionary:", merged_dict)

Explanation:
To merge two dictionaries in Python, you can use
 the update() method, the unpacking operator **, or the merge operator | introduced in Python 3.9.

86) How do you remove duplicates from a list in Python?

def remove_duplicates(lst):
    return list(set(lst))

original_list = [1, 2, 2, 3, 4, 4, 5]
print("Without duplicates:", remove_duplicates(original_list))

Explanation: To remove duplicates from a list, you can convert the list to a set and then back to a list,
 as sets automatically remove duplicates: list(set(my_list)).

87) How do you check if a string is a palindrome in Python?

def is_palindrome(s):
    return s == s[::-1]

print(is_palindrome("radar"))  # Output: True
print(is_palindrome("python")) # Output: False

Explanation: This function checks if a string is a palindrome by comparing it to its reverse.

88) How do you reverse a list in Python?

def reverse_list(lst):
    return lst[::-1]

original_list = [1, 2, 3, 4, 5]
print("Reversed list:", reverse_list(original_list))

Explanation: This function reverses a list using the slicing technique.

89)How do you convert a string to a list of characters in Python?

s = "hello"
a = list(s)
print(a)

#Output: ['h', 'e', 'l', 'l', 'o']

90) How do you check if a string contains only digits?

def contains_only_digits(s):
    return s.isdigit()

print(contains_only_digits("12345"))  # Output: True
print(contains_only_digits("123a45")) # Output: False

91) How do you sort a list of dictionaries in Python based on a specific key?


from operator import itemgetter
list_of_dicts = [{'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 20}, {'name': 'Charlie', 'age': 30}]
sorted_list = sorted(list_of_dicts, key=itemgetter('age'))
print(sorted_list)

Explanation: This code sorts a list of dictionaries based on the age key using the sorted() function and itemgetter from the operator module.

92) How do you remove all duplicates from a list ?

def remove_duplicates(lst):
    return list(set(lst))

my_list = [1, 2, 2, 3, 4, 4, 5]
print(remove_duplicates(my_list))

Explanation: This function removes duplicates by converting the list to a set,
which automatically removes duplicate elements, and then converting it back to a list.

93) How do you check if a string contains a specific substring in Python?

def contains_substring(string, substring):
    return substring in string

print(contains_substring("hello world", "world"))  # Output: True

Explanation: This function checks if a substring exists within a string using the in keyword.

94) How do you sort a list of strings in alphabetical order?

def sort_strings(lst):
    return sorted(lst)

my_list = ["banana", "apple", "cherry"]
print(sort_strings(my_list))

Explanation: This function sorts a list of strings in alphabetical order using the sorted() function.

95) How do you iterate over a dictionary in Python?

my_dict = {'a': 1, 'b': 2, 'c': 3}
for key, value in my_dict.items():
    print(f"Key: {key}, Value: {value}")
Explanation:
This code iterates over a dictionary, accessing both keys and values using the .items() method.

96) How do you remove duplicates from a list in Python?

def remove_duplicates(lst):
    return list(dict.fromkeys(lst))

my_list = [1, 2, 2, 3, 4, 4, 5]
print(remove_duplicates(my_list))

Explanation: This function removes duplicates using a dictionary to preserve order, as dictionary keys are unique.

97) What is the output of the following code?

a = [1, 2, 3]
b = a
a.append(4)
print(b)
Output: [1][2][3][4]

Explanation: Since b is a reference to the same list as a, changes to a will reflect in b.

98) How do you reverse a string in Python?

def reverse_string(s):
    return s[::-1]

print(reverse_string("hello"))  # Output: "olleh"
Explanation: This function reverses a string using slicing.

99) How do you find the length of a list in Python?

my_list = [1, 2, 3, 4, 5]
print(len(my_list))  # Output: 5

Explanation: The len() function is used to find the number of items in a list.

100) How do you check if a list is empty in Python?

def is_list_empty(lst):
    return not lst

print(is_list_empty([]))  # Output: True
print(is_list_empty([1, 2, 3]))  # Output: False

Explanation: This function checks if a list is empty by evaluating the truthiness of the list.
An empty list evaluates to False, so not lst returns True for an empty list.