Lists-Array Flashcards

1
Q

Check if any two intervals intersects among a given set of intervals.
An interval is represented as a combination of start time and end time. Given a set of intervals, check if any two intervals intersect.

Input: arr[] = {{1, 3}, {5, 7}, {2, 4}, {6, 8}}
Output: true
The intervals {1, 3} and {2, 4} overlap

A

time_complexity: nlog(n) (sorting) + n= nlog(n)

def check(array):
    array.sort(key = lambda x: x[0])
for i in range(1, len(array)):
    if  array[i][0] <= array[i-1][1]:
        return (True)

return False
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Check if a subarray with 0 sum exists or not.

Given an integer array, check if it contains a subarray having zero-sum.

Input: { 3, 4, -7, 3, 1, 3, 1, -4, -2, -2 }

Output: Subarray with zero-sum exists

The subarrays with a sum of 0 are:

{ 3, 4, -7 }
{ 4, -7, 3 }
{ -7, 3, 1, 3 }
{ 3, 1, -4 }
{ 3, 1, 3, 1, -4, -2, -2 }
{ 3, 4, -7, 3, 1, 3, 1, -4, -2, -2 }
A

We can easily solve this problem in linear time by using hashing. The idea is to use a set to check if a subarray with zero-sum is present in the given array or not. Traverse the array and maintain the sum of elements seen so far. If the sum is seen before (i.e., the sum exists in the set), return true as there exists at least one subarray with zero-sum that ends at the current index; otherwise, insert the sum into the set.

The time complexity of the above solution is O(n) and requires O(n) extra space, where n is the size of the input.

def hasZeroSumSublist(nums):
    check_set = set()
    check_set.add(0)
    sum_=0
    for i in range(len(nums)):
        sum_+=nums[i]
        if sum_ in check_set:
            print("sub array with zero exists")
    check_set.add(sum_)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

what is Multimap?

write a utility function to insert value to multi map

A

A Multimap is a map that allows the mapping of a single key to multiple values.
example: d ={A:[1,2,4], B:[3,5,6]}

def insert (d, key, value):
      d.setdeafult ( key,[ ]).append(value)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Print all subarrays with 0 sum

Given an integer array, print all subarrays with zero-sum.

input: { 4, 2, -3, -1, 0, 4 }

Subarrays with zero-sum are

{ -3, -1, 0, 4 }
{ 0 }

A

We can use multimap to print all subarrays with a zero-sum present in the given array. The idea is to create an empty multimap to store all subarrays’ ending index having a given sum. Traverse the array and maintain the sum of elements seen so far. If the sum is seen before, at least one subarray has zero-sum, which ends at the current index. Finally, print all such subarrays.
___ Time complexity is n2. we calculate sum in linear time. otherwise in Brute Force we had n3. n2 for all sub arrays and n for sum.

******* code*********************
# Utility function to insert  into the dictionary

def insert(d, key, value):

    # if the key is seen for the first time, initialize the list
    d.setdefault(key, []).append(value)
# Function to print all sublists with a zero-sum present in a given list
def printallSublists(nums):
    # create an empty dictionary to store the ending index of all
    # sublists having the same sum
    d = {}
    # insert (0, -1) pair into the dictionary to handle the case when
    # sublist with zero-sum starts from index 0
    insert(d, 0, -1)
total = 0
    # traverse the given list
    for i in range(len(nums)):
        # sum of elements so far
        total += nums[i]
        # if the sum is seen before, there exists at least one
        # sublist with zero-sum
        if total in d:
        list = d.get(total)
            # find all sublists with the same sum
            for value in list:
                print('Sublist is', (value + 1, i))
        # insert (sum so far, current index) pair into the dictionary
        insert(d, total, I)

https://www.techiedelight.com/find-sub-array-with-0-sum/

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Sort binary array in linear time
Given a binary array, sort it in linear time and constant space. The output should print all zeroes, followed by all ones.

A

this question is similar to move zeros to left in linear time and constant space:

def sort_binary(nums):
    read_idx = len(nums)-1
    write_idx = len(nums)-1
    while read_idx > 0 :
        if nums[read_idx]!=0:
            nums[write_idx]= nums[read_idx]
            write_idx-=1
        read_idx -=1
    while write_idx >0:
        nums[write_idx]=0
    write_idx-=1
return nums

or

# Function to sort a binary list in linear time
def sort(A):
    # count number of 0's
    zeros = A.count(0)
    # put 0's at the beginning
    k = 0
    while zeros:
        A[k] = 0
        zeros = zeros - 1
        k = k + 1
    # fill all remaining elements by 1
    for k in range(k, len(A)):
        A[k] = 1

if __name__ == ‘__main__’:

A = [0, 0, 1, 0, 1, 1, 0, 1, 0, 0]

sort(A)
    # print the rearranged list
    print(A)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Find the duplicate element in a limited range array

Given a limited range array of size n containing elements between 1 and n-1 with one element repeating, find the duplicate number in it without using any extra space.

A

We have limited range arry!!!

Approach 1: Using Hashing
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_-
The idea is to use hashing to solve this problem. We can use a visited boolean array to mark if an element is seen before or not. If the element is already encountered before, the visited array will return true.
*******************************
def findDuplicate(nums):
    # create a visited list of size `n+1`
    # we can also use a dictionary instead of a visited list
    visited = [False] * (len(nums) + 1)
    # for each element in the list, mark it as visited and
    # return it if seen before
    for i in nums:
        # if the element is seen before
        if visited[i]:
            return i
        # mark element as visited
        visited[i] = True
    # no duplicate found
    return -1

_____________________

Approach 4: Using Difference in Sum

def findDuplicate(nums):

actual_sum = sum(nums)
expected_sum = len(nums) * (len(nums) - 1) // 2

return actual_sum - expected_sum
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

what is the difference between subarray and subsequense?

A

Unlike subsequences, subarrays are required to occupy consecutive positions within the original array.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Find the largest subarray formed by consecutive integers.

Given an integer array, find the largest subarray formed by consecutive integers. The subarray should contain all distinct values.

Input: { 2, 0, 2, 1, 4, 3, 1, 0 }

Output: The largest subarray is { 0, 2, 1, 4, 3 }

A

It is asked for subarray–> we need consecutive numbers
For a subarray to contain consecutive integers,

The difference between the maximum and minimum element in it should be exactly equal to the subarray’s length minus one.

All elements in the array should be distinct (we can check this by inserting the elements in a set or using a visited array).

we need two functions:

Function to check if subarray A[i…j] is formed by consecutive integers.
# Here, min and max denote the minimum and maximum element in the subarray.
O(n3)
________Code
def isConsecutive(A, i, j, min, max):

    # for a list to contain consecutive integers, the difference
    # between the maximum and minimum element in it should be exactly `j-i`
    if max - min != j - i:
        return False
    # create a visited list (we can also use a set)
    visited = [False] * (j - i + 1)
    # traverse the sublist and check if each element appears
    # only once
    for k in range(i, j + 1):
        # if the element is seen before, return false
        if visited[A[k] - min]:
            return False
        # mark the element as seen
        visited[A[k] - min] = True
    # we reach here when all elements in the list are distinct
    return True

Find the largest sublist formed by consecutive integers

def findMaxSublist(A):

length = 1
start = end = 0

# consider each sublist formed by `A[i…j]`
    # `i` denotes the beginning of the sublist
    for i in range(len(A) - 1):
        # stores the minimum and maximum element formed by `A[i…j]`
        min_val = A[i]
        max_val = A[i]
        # `j` denotes the end of the sublist
        for j in range(i + 1, len(A)):
            # update the minimum and maximum elements of the sublist
            min_val = min(min_val, A[j])
            max_val = max(max_val, A[j])
            # check if `A[i…j]`is formed by consecutive integers
            if isConsecutive(A, i, j, min_val, max_val):
                if length < max_val - min_val + 1:
                    length = max_val - min_val + 1
                    start = i
                    end = j
    # print the maximum length sublist
    print("The largest sublist is", (start, end))
# Find the largest sublist formed by consecutive integers
def findMaxSublist(A):
length = 1
start = end = 0

# consider each sublist formed by `A[i…j]`
    # `i` denotes the beginning of the sublist
    for i in range(len(A) - 1):
        # stores the minimum and maximum element formed by `A[i…j]`
        min_val = A[i]
        max_val = A[i]
        # `j` denotes the end of the sublist
        for j in range(i + 1, len(A)):
            # update the minimum and maximum elements of the sublist
            min_val = min(min_val, A[j])
            max_val = max(max_val, A[j])
            # check if `A[i…j]`is formed by consecutive integers
            if isConsecutive(A, i, j, min_val, max_val):
                if length < max_val - min_val + 1:
                    length = max_val - min_val + 1
                    start = i
                    end = j
    # print the maximum length sublist
    print("The largest sublist is", (start, end))
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Find maximum length subarray having a given sum

Given an integer array, find the maximum length subarray having a given sum.

A

A naive solution is to consider all subarrays and find their sum. If the subarray sum is equal to the given sum, update the maximum length subarray. The time complexity of the naive solution is O(n3) as there are n2 subarrays in an array of size n, and it takes O(n) time to find the sum of its elements. We can optimize the method to run in O(n2) time by calculating the subarray sum in constant time.

However,
We can use a map to solve this problem in linear time. The idea is to create an empty map to store the first subarray’s ending index, having a given sum. We traverse the given array and maintain the sum of elements seen so far.

If the target is seen for the first time, insert the sum with its index into the map.
If target-S is seen before, there is a subarray with the given sum that ends at the current index, and we update the maximum length subarray having sum S if the current subarray has more length.

https://www.techiedelight.com/find-maximum-length-sub-array-having-given-sum/

**********************************************
# Find maximum length sublist with sum `S` present in a given list
def findMaxLenSublist(nums, S):
    # create an empty dictionary to store the ending index of the first
    # sublist having some sum
    d = {}
    # insert (0, -1) pair into the set to handle the case when a
    # sublist with sum `S` starts from index 0
    d[0] = -1
target = 0
    # `length` stores the maximum length of sublist with sum `S`
    length = 0
    # stores ending index of the maximum length sublist having sum `S`
    ending_index = -1
    # traverse the given list
    for i in range(len(nums)):
        # target of elements so far
        target += nums[i]
        # if the sum is seen for the first time, insert the sum with its
        # into the dictionary
        if target not in d:
            d[target] = i
        # update length and ending index of the maximum length sublist
        # having sum `S`
        if target - S in d and length < i - d[target - S]:
            length = i - d[target - S]
            ending_index = i
    # print the sublist
    print((ending_index - length + 1, ending_index))

if __name__ == ‘__main__’:

nums = [5, 6, -5, 5, 3, 5, 3, -2, 0]
target = 8

findMaxLenSublist(nums, target)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Find the largest subarray having an equal number of 0’s and 1’s
Given a binary array containing 0’s and 1’s, find the largest subarray with equal numbers of 0’s and 1’s.

A

A naive solution would be to consider all subarrays and, for each subarray, count the total number of 0’s and 1’s present. If the subarray contains an equal number of 0’s and 1’s, update the largest subarray if required. The time complexity of the naive solution is O(n3) as there are n2 subarrays in an array of size n, and it takes O(n) time to find count 0’s and 1’s. We can optimize the method to run in O(n2) time by calculating the count of 0’s and 1’s in constant time.

We can use the map to solve this problem in linear time. The idea is to replace 0 with -1 and find out the largest subarray with a sum of 0. To find the largest subarray with a sum of 0, create an empty map that stores the first subarray’s ending index having a given sum. Then traverse the given array and maintain the sum of elements seen so far.

If the sum is seen for the first time, insert the sum with its index into the map.
If the sum is seen before, there exists a subarray with a sum of 0, which ends at the current index, and update the largest subarray if the current subarray has more length.

################## code###########
def findLargestSublist(nums):
    # create an empty dictionary to store the ending index of the first
    # sublist having some sum
    d = {}
    # insert (0, -1) pair into the set to handle the case when a
    # sublist with zero-sum starts from index 0
    d[0] = -1
    # `length` stores the maximum length of sublist with zero-sum
    length = 0
    # stores ending index of the largest sublist having zero-sum
    ending_index = -1
total = 0
    # Traverse through the given list
    for i in range(len(nums)):
        # sum of elements so far (replace 0 with -1)
        total += -1 if (nums[i] == 0) else 1
        # if the sum is seen before
        if total in d:
            # update length and ending index of largest sublist having zero-sum
            if length < i - d.get(total):
                length = i - d.get(total)
                ending_index = i
        # if the sum is seen for the first time, insert the sum with its
        # index into the dictionary
        else:
            d[total] = i
    # print the sublist if present
    if ending_index != -1:
        print((ending_index - length + 1, ending_index))
    else:
        print('No sublist exists')

if __name__ == ‘__main__’:

nums = [0, 0, 1, 0, 1, 0, 0]
findLargestSublist(nums)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Sort an array of 0’s, 1’s, and 2’s (Dutch National Flag Problem)

Given an array containing only 0’s, 1’s, and 2’s, sort it in linear time and using constant space.

A

A simple solution would be to perform a counting sort. We count the total number of 0’s, 1’s, and 2’s and then put them in the array in their correct order. The time complexity of this solution is O(n), where n is the size of the input. However, this requires two traversals of the array.

We can rearrange the array in a single traversal using an alternative linear-time partition routine that separates the values into three groups:

The values less than the pivot,
The values equal to the pivot, and
The values greater than the pivot.

The time complexity of the above solution is O(n) and doesn’t require any extra space, where n is the size of the input.

********* code*******************************
# Utility function to swap elements `A[i]` and `A[j]` in the list
def swap(A, i, j):
temp = A[i]
A[i] = A[j]
A[j] = temp
# Linear time partition routine to sort a list containing 0, 1, and 2.
# It is similar to 3–way partitioning for the Dutch national flag problem.
def threeWayPartition(A):
start = mid = 0
pivot = 1
end = len(A) - 1

while mid <= end:
    if A[mid] < pivot:      # current element is 0
        swap(A, start, mid)
        start = start + 1
        mid = mid + 1
    elif A[mid] > pivot:    # current element is 2
        swap(A, mid, end)
        end = end - 1
    else:                   # current element is 1
        mid = mid + 1

if __name__ == ‘__main__’:

A = [0, 1, 2, 2, 1, 0, 0, 2, 0, 1, 1, 0]
threeWayPartition(A)
print(A)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

In-place merge two sorted arrays

Given two sorted arrays, X[] and Y[] of size m and n each, merge elements of X[] with elements of array Y[] by maintaining the sorted order, i.e., fill X[] with the first m smallest elements and fill Y[] with remaining elements.

Input:

X[] = { 1, 4, 7, 8, 10 }
Y[] = { 2, 3, 9 }

Output:

X[] = { 1, 2, 3, 4, 7 }
Y[] = { 8, 9, 10 }
A

The idea is simple. Consider each array element X[] and ignore it if it is already in the correct order (i.e., the element smallest among all remaining elements); otherwise, swap it with the smallest element, which happens to be the first element of Y[]. After swapping, move the element (now present at Y[0]) to its correct position in Y[] to maintain the sorted order.

The time complexity of the above solution is O(m.n), where m is the size of the first array and n is the size of the second array. The solution doesn’t require any extra space. The problem, in fact, can be solved in linear time and constant space. This approach is highly complicated and is discussed here.

###### code############
# Function to in-place merge two sorted lists `X` and `Y`
# invariant: `X` and `Y` are sorted at any point
def merge(X, Y):
m = len(X)
n = len(Y)
    # Consider each element `X[i]` of list `X[]` and ignore the element if it is
    # already in the correct order; otherwise, swap it with the next smaller
    # element, which happens to be the first element of `Y[]`.
    for i in range(m):
        # compare the current element of `X[]` with the first element of `Y[]`
        if X[i] > Y[0]:
            # swap `X[i] with `Y[0]`
            temp = X[i]
            X[i] = Y[0]
            Y[0] = temp
        first = Y[0]
            # move `Y[0]` to its correct position to maintain the sorted
            # order of `Y[]`. Note: `Y[1…n-1]` is already sorted
            k = 1
            while k < n and Y[k] < first:
                Y[k - 1] = Y[k]
                k = k + 1
        Y[k - 1] = first

if __name__ == ‘__main__’:

X = [1, 4, 7, 8, 10]
Y = [2, 3, 9]

merge(X, Y)

print("X:", X)
print("Y:", Y)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Merge two arrays by satisfying given constraints

Given two sorted arrays X[] and Y[] of size m and n each where m >= n and X[] has exactly n vacant cells, merge elements of Y[] in their correct position in array X[], i.e., merge (X, Y) by keeping the sorted order.

Input:

X[] = { 0, 2, 0, 3, 0, 5, 6, 0, 0 }
Y[] = { 1, 8, 9, 10, 15 }

The vacant cells in X[] is represented by 0

Output:

X[] = { 1, 2, 3, 5, 6, 8, 9, 10, 15 }

A

The idea is simple – move non-empty elements of X[] at the beginning of X[] and then merge X[] with Y[] starting from the end. The merge process is similar to the merge routine of the merge sort algorithm.
O(m+n)

##############code######
## merge with constrain
def rearrange(X, Y):
    if len(X)==0:
        return;
    ## movens non empty elemnt of x and count the number of non zero of X
    k = 0 ## for saving the space of non zero
    for i in range(len(X)):
        if X[i]:
            X[k] =X[i]
            k+=1
merge(X,Y,k-1, len(Y)-1 )

def merge(X, Y, m, n):

    l = m+n+1
    ## the new array will be filled out from th end which is l
    while m>=0 and  n>=0:
        if X[m]> Y[n]:
            X[l] = X[m]
            l-=1
            m-=1
        else:
            X[l] = Y[n]
            l-=1
            n-=1
    while n>=0:
        X[l] = Y[n]
        l-=1
        n-=1
    for i in range(len(Y)):
        Y[i] = 0

if __name__ == ‘__main__’:

# vacant cells in `X[]` is represented by 0
X = [0, 2, 0, 3, 0, 5, 6, 0, 0]
Y = [1, 8, 9, 10, 15]

''' Validate input before calling `rearrange()`

    1. Both lists `X[]` and `Y[]` should be sorted (ignore 0's in `X[]`)
    2. Size of list `X[]` >= size of list `Y[]` (i.e., `m >= n`)
    3. Total number of vacant cells in list `X[]` = size of list `Y[]` '''
    # merge `Y` into `X`
    rearrange(X, Y)
    # print merged list 
    print(X)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Find the index of 0 to be replaced to get the maximum length sequence of continuous ones

Given a binary array, find the index of 0 to be replaced with 1 to get the maximum length sequence of continuous ones.

A

the problem can solved in O(n) time. The idea is to keep track of three indexes, current index (curr), previous zero index (prev_zero) and previous to previous zero index (prev_prev_zero).

Traverse the array, if current element is 0, calculate the difference between curr and prev_prev_zero (This difference minus one is the number of 1s around the prev_zero). If the difference between curr and prev_prev_zero is more than maximum so far, then update the maximum. Finally return index of the prev_zero with maximum difference.

def maxOnesIndex(arr,n):

    # for maximum number of 1 around a zero
    max_count = 0
    # for storing result 
    max_index =0 
    # index of previous zero
    prev_zero = -1 
    # index of previous to previous zero
    prev_prev_zero = -1
    # Traverse the input array
    for curr in range(n):
        # If current element is 0,
        # then calculate the difference
        # between curr and prev_prev_zero
        if (arr[curr] == 0):
            # Update result if count of
            # 1s around prev_zero is more
            if (curr - prev_prev_zero > max_count):
            max_count = curr - prev_prev_zero
            max_index = prev_zero
            # Update for next iteration
            prev_prev_zero = prev_zero
            prev_zero = curr
    # Check for the last encountered zero
    if (n-prev_prev_zero > max_count):
        max_index = prev_zero
return max_index

Driver program

arr = [1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1]
n = len(arr)

print(“Index of 0 to be replaced is “,
maxOnesIndex(arr, n))

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Find the maximum product of two integers in an array

Given an integer array, find the maximum product of two integers in it.

For example, consider array {-10, -3, 5, 6, -2}. The maximum product is the (-10, -3) or (5, 6) pair.

A
A naive solution is to consider every pair of elements and calculate their product. Update the maximum product found so far if the product of the current pair is greater. Finally, print the elements involved in the maximum product.
O(n2)
####### code#######

import sys

# A naive solution to finding the maximum product of two integers in a list
def findMaximumProduct(A):
    # base case
    if len(A) < 2:
        return
max_product = -sys.maxsize
max_i = max_j = -1

# consider every pair of elements
for i in range(len(A) - 1):
    for j in range(i + 1, len(A)):
        # update the maximum product if required
        if max_product < A[i] * A[j]:
            max_product = A[i] * A[j]
            (max_i, max_j) = (i, j)

print("Pair is", (A[max_i], A[max_j]))

if __name__ == ‘__main__’:

A = [-10, -3, 5, 6, -2]
findMaximumProduct(A)

_____________________
O(nlogn)

The time complexity can be improved by sorting the array. Then the result is the maximum of the following:

The product of maximum and second maximum integer in the array (i.e., the last two elements in a sorted array).
The product of minimum and second minimum integers in the array (i.e., the first two elements in the sorted array).

# A naive solution to finding the maximum product of two integers in a list
def findMaximumProduct(A):
    # `n` is the length of the list
    n = len(A)
    # base case
    if n < 2:
        return
    # sort list in ascending order
    A.sort()
    # choose the maximum of the following:
    # 1. Product of the first two elements or
    # 2. Product of the last two elements.
if (A[0] * A[1]) > (A[n - 1] * A[n - 2]):
    print("Pair is", (A[0], A[1]))
else:
    print("Pair is", (A[n - 1], A[n - 2]))

if __name__ == ‘__main__’:

A = [-10, -3, 5, 6, -20]
findMaximumProduct(A)

__________________________
We can solve this problem in linear time as we need the only maximum, second maximum, minimum, and second minimum elements to solve this problem. We can compute all these in only a single traversal of the array, which accounts for O(n) time complexity.

import sys

# Function to find the maximum product of two integers in a list
def findMaximumProduct(A):
    # to store the maximum and second maximum element in a list
    max1 = A[0]
    max2 = -sys.maxsize
    # to store the minimum and second minimum element in a list
    min1 = A[0]
    min2 = sys.maxsize
for i in range(1, len(A)):
        # if the current element is more than the maximum element,
        # update the maximum and second maximum element
        if A[i] > max1:
            max2 = max1
            max1 = A[i]
        # if the current element is less than the maximum but greater than the
        # second maximum element, update the second maximum element
        elif A[i] > max2:
            max2 = A[i]
        # if the current element is less than the minimum element,
        # update the minimum and the second minimum
        if A[i] < min1:
            min2 = min1
            min1 = A[i]
        # if the current element is more than the minimum but less than the
        # second minimum element, update the second minimum element
        elif A[i] < min2:
            min2 = A[i]
    # otherwise, ignore the element

# choose the maximum of the following:
# 1. Product of the maximum and second maximum element or
# 2. Product of the minimum and second minimum element
if max1 * max2 > min1 * min2:
    print("Pair is", (max1, max2))
else:
    print("Pair is", (min1, min2))

if __name__ == ‘__main__’:

A = [-10, -3, 5, 6, -2]
findMaximumProduct(A)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

what is Fisher–Yates shuffle?

A

is an algorithm to generate random permutations. It takes time proportional to the total number of items being shuffled and shuffles them in place. The algorithm swaps the element at each iteration at random among all remaining unvisited indices, including the element itself.

Here’s the complete algorithm:

— To shuffle an array ‘a’ of ‘n’ elements:
for i from n-1 down to 1 do
j = random integer such that 0 <= j <= i
exchange a[j] and a[i]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Shuffle an array using Fisher–Yates shuffle algorithm

Given an integer array, in-place shuffle it. The algorithm should produce an unbiased permutation, i.e., every permutation is equally likely.

A

Fisher–Yates shuffle is an algorithm to generate random permutations. It takes time proportional to the total number of items being shuffled and shuffles them in place. The algorithm swaps the element at each iteration at random among all remaining unvisited indices, including the element itself.

O(n)

############# Code
from random import randrange
def swap(A, i, j):
    temp = A[i]
    A[i] = A[j]
    A[j] = temp

def inplace_shuffle(A):

for i in reversed(range(1,len(A))):
    j = randrange(i+1)
    swap(A, j, i)

if __name__ == ‘__main__’:

A = [1, 2, 3, 4, 5, 6]

inplace_shuffle(A)
    # print the shuffled list
    print(A)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Rearrange an array with alternate high and low elements

Rearrange an array with alternate high and low elements

Input: {9, 6, 8, 3, 7}
Output: {6, 9, 3, 8, 7}

A
Solution 1:
RearrangeArray(arr[], n)
Sort the array in ascending order.
Take two index variables i and j to that point to two endpoints of the array (i.e., i = 0 and j = n-1).
Create an auxiliary array A[] and initialize an index k with 0.
Do while (i < j)
    A[k++] = arr[i++]
    A[k++] = arr[j–]
Print A[].

O(nlogn)

############
Solution 2:
without sorting.

An efficient solution doesn’t involve sorting the array or the use of extra space. The idea is to start from the second array element and increment the index by 2 for each loop’s iteration. If the last element is greater than the current element, swap the elements. Similarly, if the next element is greater than the current element, swap both elements. At the end of the loop, we will get the desired array that satisfies given constraints.

######## coding
# Utility function to swap elements `A[i]` and `A[j]` in the list
def swap(A, i, j):
temp = A[i]
A[i] = A[j]
A[j] = temp
# Function to rearrange the list such that every second element
# of the list is greater than its left and right elements
def rearrangeArray(A):
    # start from the second element and increment index
    # by 2 for each iteration of the loop
    for i in range(1, len(A), 2):
    # if the previous element is greater than the current element,
    # swap the elements
    if A[i - 1] > A[i]:
        swap(A, i - 1, i)

    # if the next element is greater than the current element,
    # swap the elements
    if i + 1 < len(A) and A[i + 1] > A[i]:
        swap(A, i + 1, i)

if __name__ == ‘__main__’:

A = [9, 6, 8, 3, 7]

re_arrange(A)
    # print output list
    print(A)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Find equilibrium index of an array

Given an integer array, find the equilibrium index in it.

For an array A consisting n elements, index i is an equilibrium index if the sum of elements of subarray A[0…i-1] is equal to the sum of elements of subarray A[i+1…n-1]. i.e.

(A[0] + A[1] + … + A[i-1]) = (A[i+1] + A[i+2] + … + A[n-1]), where 0 < i < n-1

Similarly, 0 is an equilibrium index if A[1] + A[2] + … + A[n-1] sums to 0 and n-1 is an equilibrium index if A[0] + A[1] + … + A[n-2] sums to 0.

A

A naive solution would be to calculate the sum of elements to the left and the sum of elements to each array element’s right. If the left subarray sum is the same as the right subarray sum for an element, print its index. The time complexity of this solution is O(n2), where n is the size of the input

  1. Linear-time Solution
    We can solve this problem in linear time by using extra space. The idea is to create an auxiliary array left[], where left[i] stores a sum of elements of the subarray A[0…i-1]. After left[] is filled, traverse the array from right to left and update them right subarray sum for each element encountered. Now, if the sum of elements of the left subarray A[0…i-1] is equal to the sum of elements of the right subarray A[i+1…n) for element A[i], we have found the equilibrium index at I.
############coding
# Function to find the equilibrium index of a list
def findEquilibriumIndex(A):
    # `left[i]` stores the sum of elements of sublist `A[0…i-1]`
    left = [0] * len(A)
    # traverse the list from left to right
    for i in range(1, len(A)):
        left[i] = left[i - 1] + A[i - 1]
    # `right` stores the sum of elements of sublist `A[i+1…n)`
    right = 0
    # maintain a list of indices
    indices = []
    # traverse the list from right to left
    for i in reversed(range(len(A))):
    ''' if the sum of elements of sublist `A[0…i-1]` is equal to
        the sum of elements of sublist `A[i+1…n)` i.e.
        `(A[0] + … + A[i-1]) = (A[i+1] + A[i+2] + … + A[n-1])` '''

    if left[i] == right:
        indices.append(i)
        # new right is `A[i] + (A[i+1] + A[i+2] + … + A[n-1])`
        right += A[i]
print("Equilibrium Index found at", indices)

if __name__ == ‘__main__’:

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

findEquilibriumIndex(A)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Boyer–Moore Majority Vote Algorithm

Given an integer array containing duplicates, return the majority element if present. A majority element appears more than n/2 times, where n is the array size.

For example, the majority element is 2 in array {2, 8, 7, 2, 2, 5, 2, 3, 1, 2, 2}.

A

Approach 1:
O(N)

Linear-time Solution
We can use hashing to solve this problem in linear time. The idea is to store each element’s frequency in a map and return it if its frequency becomes more than n/2. If no such element is present, then the The majority element doesn’t exist in the array, and return -1.
### coding###
# Function to find the majority element present in a given list
def findMajorityElement(nums):
    # create an empty `HashMap`
    d = {}
    # store each element's frequency in a dictionary
    for i in nums:
        d[i] = d.get(i, 0) + 1
# return the element if its count is more than `n/2`
for key, value in d.items():
    if value > len(nums) / 2:
        return key
    # no majority element is present
    return -1

if __name__ == ‘__main__’:

    # assumption: valid input (majority element is present)
    nums = [1, 8, 7, 4, 1, 2, 2, 2, 2, 2, 2]
result = findMajorityElement(nums)
if result != -1:
    print('The majority element is', result)
else:
    print('The majority element doesn\'t exist')

Download Run Code

Output:

The majority element is 2

The time complexity of the above solution is O(n) and requires O(n) extra space.

  1. Boyer–Moore majority vote algorithm
    We can find the majority element using linear time and constant space using the Boyer–Moore majority vote algorithm. The algorithm can be expressed in pseudocode as the following steps:

Initialize an element m and a counter i = 0

 for each element x of the input sequence:
   if i = 0, then
     assign m = x and i = 1
   else
     if m = x, then assign i = i + 1
   else
     assign i = i – 1
 return m
The algorithm processes each element of the sequence, one at a time. When processing an element x,

If the counter is 0, set the current candidate to x, and set the counter to 1.
If the counter is non-zero, increment or decrement it according to whether x is a current candidate.
At the end of this process, if the sequence has a majority, it will be the element stored by the algorithm. If there is no majority element, the algorithm will not detect that fact and may output the wrong element. In other words, the Boyer–Moore majority vote algorithm produces correct results only when the majority element is present in the input.

The algorithm can be implemented as follows in C, Java, and Python. It is recommended to modify the algorithm to verify if the returned element is, in fact, a majority element or not.

# Function to find the majority element present in a given list
def findMajorityElement(nums):
    # `m` stores the majority element (if present)
    m = -1
    # initialize counter `i` with 0
    i = 0
    # do for each element `nums[j]` in the list
    for j in range(len(nums)):
        # if counter `i` becomes 0
        if i == 0:
            # set the current candidate to `nums[j]`
            m = nums[j]
            # reset the counter to 1
            i = 1
        # otherwise, increment the counter if `nums[j]` is a current candidate
        elif m == nums[j]:
            i = i + 1
        # otherwise, decrement the counter if `nums[j]` is a current candidate
        else:
            i = i - 1
return m

if __name__ == ‘__main__’:

    # assumption: valid input (majority element is present)
    nums = [1, 8, 7, 4, 1, 2, 2, 2, 2, 2, 2]
print('The majority element is', findMajorityElement(nums))

_______________________________-
Approach 2
We can improve worst-case time complexity to O(n.log(n)) by sorting the array and then perform a binary search for each element’s first and last occurrence. If the difference between first and last occurrence is more than n/2, the The majority element is found.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Move all zeros present in an array to the end

Given an integer array, move all zeros present in it to the end. The solution should maintain the relative order of items in the array and should not use constant space.

A

The idea is simple – if the current element is non-zero, place the element at the next available position in the array. After all elements in the array are processed, fill all remaining indices by 0. This approach is demonstrated below in

############## code#########
# Function to move all zeros present in the list to the end
def reorder(A):
    # `k` stores the index of the next available position
    k = 0
    # do for each element
    for i in A:
        # if the current element is non-zero, put the element at the
        # next free position in the list
        if i:
            A[k] = i
            k = k + 1
    # move all 0's to the end of the list (remaining indices)
    for i in range(k, len(A)):
        A[i] = 0

if __name__ == ‘__main__’:

A = [6, 0, 8, 2, 3, 0, 4, 0, 1]

reorder(A)
print(A)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Replace every array element with the product of every other element without using a division operator

Given an integer array, replace each element with the product of every other element without using the division operator.

Input: { 1, 2, 3, 4, 5 }
Output: { 120, 60, 40, 30, 24 }

A

A naive solution would be to calculate the product of all elements in the left and right subarray for each array element. The time complexity of this approach is O(n2), where n is the size of the input.

We can solve this problem in linear time by using two auxiliary arrays, left[] and right[], where left[i] stores the product of all elements in subarray A[0…i-1] and right[i] stores the product of all elements in subarray A[i+1…n-1]. Now for each element A[i], replace it with the product of its left-subarray and right-subarray (i.e., A[i] = left[i] × right[i]).

########### code
# Function to replace each array element with every other
# element's product without using the division operator
def findProduct(A):
    # get length of the list
    n = len(A)
    # base case
    if n == 0:
        return
# use two auxiliary lists
left = [None] * n
right = [None] * n
    # `left[i]` stores the product of all elements in sublist `A[0…i-1]`
    left[0] = 1
    for i in range(1, n):
        left[i] = A[i - 1] * left[i - 1]
    # `right[i]` stores the product of all elements in sublist `A[i+1…n-1]`
    right[n - 1] = 1
    for j in reversed(range(n - 1)):
        right[j] = A[j + 1] * right[j + 1]
    # replace each element with the product of its left and right sublist
    for i in range(n):
        A[i] = left[i] * right[i]

if __name__ == ‘__main__’:

A = [5, 3, 4, 2, 6, 8]
findProduct(A)
    # print the modified list
    print(A)
23
Q

Longest Bitonic Subarray Problem

The Longest Bitonic Subarray (LBS) problem is to find a subarray of a given sequence in which the subarray’s elements are first sorted in increasing order, then in decreasing order, and the subarray is as long as possible. Strictly ascending or descending subarrays are also accepted.

Longest bitonic subarray of the sequence { 3, 5, 8, 4, 5, 9, 10, 8, 5, 3, 4 } is { 4, 5, 9, 10, 8, 5, 3 }

A

The problem differs from the problem of finding the longest bitonic subsequence. Unlike subsequences, subarrays are required to occupy consecutive positions within the original array.

The idea is to maintain two arrays, I[] and D[]:

I[i] store the length of the longest increasing subarray, ending at arr[i].
D[i] store the length of the longest decreasing subarray, starting from arr[i].
Finally, the length of the longest bitonic subarray is maximum among all I[i] + D[i] - 1. We can also keep track of two endpoints of the longest bitonic subarray found so far to print LBS.

time complexity O(n), space O(n)

code

# Function to find the length of the longest bitonic subarray in a list
def findBitonicSublist(A):
    if len(A) == 0:
        return
    # `I[i]` store the length of the longest increasing sublist,
    # ending at `A[i]`
    I = [1] * len(A)
for i in range(1, len(A)):
    if A[i - 1] < A[i]:
        I[i] = I[i - 1] + 1
    # `D[i]` store the length of the longest decreasing sublist,
    # starting with `A[i]`
    D = [1] * len(A)
for i in reversed(range(len(A) - 1)):
    if A[i] > A[i + 1]:
        D[i] = D[i + 1] + 1
    # consider each element as a peak and calculate LBS
    lbs_len = 1
    beg = end = 0
    for i in range(len(A)):
        if lbs_len < I[i] + D[i] - 1:
            lbs_len = (I[i] + D[i] - 1)
            beg = i - I[i] + 1
            end = i + D[i] - 1
    # print the longest bitonic subarray
    print("The length of the longest bitonic subarray is", lbs_len)
    print("The longest bitonic subarray is", A[beg:end+1])

if __name__ == ‘__main__’:

A = [3, 5, 8, 4, 5, 9, 10, 8, 5, 3, 4]
findBitonicSublist(A)
24
Q

Find the maximum difference between two array elements that satisfies the given constraints

Given an integer array, find the maximum difference between two elements in it such that the smaller element appears before the larger element.

Input: { 2, 7, 9, 5, 1, 3, 5 }

Output: The maximum difference is 7.

The pair is (2, 9)

A

A naive solution is to consider every pair present in the array and keep track of the maximum difference found so far. O(n2)

We can solve this problem in linear time. The idea is to traverse the array from the right and keep track of the maximum difference found so far. If the current element is less than the maximum element found so far and their difference is more than the maximum difference found so far, update the maximum difference with the current difference.
O(n)

######## code:
import sys
# Function to calculate the maximum difference between two elements in a
# list such that a smaller element appears before a larger element
def getMaxDiff(A):
diff = -sys.maxsize
n = len(A)
if n == 0:
    return diff

max_so_far = A[n - 1]
    # traverse the list from the right and keep track of the maximum element
    for i in reversed(range(n - 1)):
        # update `max_so_far` if the current element is greater than the
        # maximum element
        if A[i] >= max_so_far:
            max_so_far = A[i]
        # if the current element is less than the maximum element,
        # then update the difference if required
        else:
            diff = max(diff, max_so_far - A[i])
    # return difference
    return diff

if __name__ == ‘__main__’:

A = [2, 7, 9, 5, 1, 3, 5]
diff = getMaxDiff(A)
if diff != -sys.maxsize:
    print("The maximum difference is", diff)
25
Q

Maximum Sum Subarray Problem (Kadane’s Algorithm)
Given an integer array, find a contiguous subarray within it that has the largest sum.

For example,

Input: {-2, 1, -3, 4, -1, 2, 1, -5, 4}

Output: Subarray with the largest sum is {4, -1, 2, 1} with sum 6.

A

We can easily solve this problem in linear time using Kadane’s algorithm. The idea is to maintain a maximum (positive-sum) subarray “ending” at each index of the given array. This subarray is either empty (in which case its sum is zero) or consists of one more element than the maximum subarray ending at the previous index.

If the array contains all negative values, the answer is the maximum element.

code#############

def kadane(A):

    # find the maximum element present in a given list
    maximum = max(A)
    # if the list contains all negative values, return the maximum element
    if maximum < 0:
        return maximum
    # stores the maximum sum sublist found so far
    max_so_far = 0
    # stores the maximum sum of sublist ending at the current position
    max_ending_here = 0
    # do for each element of a given list
    for i in A:
        # update the maximum sum of sublist "ending" at index `i` (by adding the
        # current element to maximum sum ending at previous index `i-1`)
        max_ending_here = max_ending_here + i
        # if the maximum sum is negative, set it to 0 (which represents
        # an empty sublist)
        max_ending_here = max(max_ending_here, 0)
        # update the result if the current sublist sum is found to be greater
        max_so_far = max(max_so_far, max_ending_here)
return max_so_far

if __name__ == ‘__main__’:

A = [-8, -3, -6, -2, -5, -4]
print("The sum of contiguous sublist with the largest sum is", kadane(A))
26
Q

Print continuous subarray with maximum sum

Given an integer array, find and print a contiguous subarray with the maximum sum in it.

For example,

Input: {-2, 1, -3, 4, -1, 2, 1, -5, 4}

Output: The contiguous subarray with the largest sum is {4, -1, 2, 1}

A

We can easily solve this problem in linear time by maintaining the maximum subarray sum ending at each array index. Then,

The subarray is either empty in which case its sum is zero, or
It consists of one more element than the maximum subarray ending at the previous index.
We have already discussed this approach using Kadane’s algorithm, but that only output the sum of contiguous subarray having the largest sum but do not print the subarray itself. We can easily modify the algorithm to keep track of the maximum subarray’s starting and ending indices.

code

def print_kadane(A):

    if len(A)<=1:
        return A
totall =0
max_totall =float("-inf")

start, end, beg =0,0,0

for i in range(len(A)):
    totall+=A[i]

    ### if the maximum sum becomes less than the current element,
    # start from the current element
    if totall < A[i]:
        totall = A[i]
        beg =i
    ## # update result if the current sublist sum is found to be greater    
    if max_totall
27
Q

1) What is a Circular array?
2) Suppose n people are sitting at a circular table with names A, B, C, D, … Given a name, we need to print all n people (in order) starting from the given name.

A

Circular array: An array is called circular if we consider the first element as next of the last element. Circular arrays are used to implement queue.

For example, consider 6 people A B C D E F and given name as ‘D’. People sitting in a circular manner starting from D are D E F A B C.
This approach takes of O(n) time but takes extra space of order O(n)
A simple solution is to create an auxiliary array of size 2*n and store it in another array. For example for 6 people, we create below the auxiliary array.
A B C D E F A B C D E F
Now for any given index, we simply print n elements starting from it. For example, we print the following 6.
A B C D E F A B C D E F

code######

circular array using extra memory space

def prints(a, n, ind):

    # Create an auxiliary array of twice size.
    b = [None]*2*n
    i = 0
    # Copy a[] to b[] two times
    while i < n:
        b[i] = b[n + i] = a[i]
        i = i + 1
i = ind

# print from ind-th index to (n+i)th index.

while i < n + ind :
    print(b[i], end = " ");
    i = i + 1

Driver Code

a = [‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’]
n = len(a);
prints(a, n, 3);

___________________________________
An efficient solution is to deal with circular arrays using the same array. If a careful observation is run through the array, then after n-th index, the next index always starts from 0 so using the mod operator, we can easily access the elements of the circular list, if we use (i)%n and run the loop from i-th index to n+i-th index. and apply mod we can do the traversal in a circular array within the given array without using any extra space.

###################### code
# function to print circular list starting
# from given index ind.
def prints(a, n, ind):
    i = ind
    # print from ind-th index to (n+i)th index.
    while i < n + ind :
        print(a[(i % n)], end = " ")
        i = i + 1
28
Q

Maximum Sum Circular Subarray

Given a circular integer array, find a subarray with the largest sum in it.
Input: {2, 1, -5, 4, -3, 1, -3, 4, -1}

Output: Subarray with the largest sum is {4, -1, 2, 1} with sum 6.

A

The idea is to find the sequence which will have a maximum negative value. If we remove that minimum sum sequence from the input sequence, we will be left with the maximum sum circular sequence. Finally, return the maximum of the maximum-sum circular sequence (includes corner elements) and maximum-sum non-circular sequence.

For example, consider array {2, 1, -5, 4, -3, 1, -3, 4, -1}. The sequence having maximum negative value is {-5, 4, -3, 1, -3}, i.e., -6. If we remove this minimum sum sequence from the array, we will get the maximum sum circular sequence, i.e., {2, 1, 4, -1} having sum 6. Since the maximum sum circular sequence is greater than the maximum sum non-circular sequence, i.e., {4} for the given array, it is the answer.

We can find the maximum-sum non-circular sequence in linear time by using Kadane’s algorithm. We can find a maximum-sum circular sequence by inverting the sign of all array elements and then applying Kadane’s algorithm.

For example, if we invert signs of array {2, 1, -5, 4, -3, 1, -3, 4, -1}, we get {-2, -1, 5, -4, 3, -1, 3, -4, 1} which has maximum sum sequence {5, -4, 3, -1, 3} having sum 6. Now inverting the signs back, we get a minimum sum sequence {-5, 4, -3, 1, -3} having sum -6.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
# Function to find contiguous sublist with the largest sum
# in a given set of integers
def kadane(A):
    # stores the sum of maximum sublist found so far
    max_so_far = 0
    # stores the maximum sum of sublist ending at the current position
    max_ending_here = 0
    # traverse the given list
    for i in range(len(A)):
        # update the maximum sum of sublist "ending" at index `i` (by adding the
        # current element to maximum sum ending at previous index `i-1`)
        max_ending_here = max_ending_here + A[i]
        # if the maximum sum is negative, set it to 0 (which represents
        # an empty sublist)
        max_ending_here = max(max_ending_here, 0)
        # update result if the current sublist sum is found to be greater
        max_so_far = max(max_so_far, max_ending_here)
return max_so_far
# Function to find the maximum sum circular sublist in a given list
def runCircularKadane(A):
    # empty array has sum of 0
    if len(A) == 0:
        return 0
    # find the maximum element present in a given list
    maximum = max(A)
    # if the list contains all negative values, return the maximum element
    if maximum < 0:
        return maximum
    # negate all elements in the list
    for i in range(len(A)):
        A[i] = -A[i]
    # run Kadane’s algorithm on the modified list
    neg_max_sum = kadane(A)
    # restore the list
    for i in range(len(A)):
        A[i] = -A[i]
''' return the maximum of the following:
    1. Sum returned by Kadane’s algorithm on the original list.
    2. Sum returned by Kadane’s algorithm on modified list +
       the sum of all elements in the list.
'''

return max(kadane(A), sum(A) + neg_max_sum)
29
Q

Find all distinct combinations of a given length

Given an integer array, find all distinct combinations of a given length k

Input: {2, 3, 4}, k = 2
Output: {2, 3}, {2, 4}, {3, 4}

A

We can use recursion to solve this problem. The idea is to add each element to the output and recur for the remaining items with one less element. To avoid printing permutations, construct each tuple in the same order as array elements. Then if the combination of the given size is found, print it.

Code

# Function to print all distinct combinations of length `k`
def findCombinations(A, k, subarrays, out=(), i=0):
    # invalid input
    if len(A) == 0 or k > len(A):
        return
# base case: combination size is `k`
if k == 0:
    subarrays.add(out)
    return
    # start from the next index till the last index
    for j in range(i, len(A)):
        # add current element `A[j]` to the solution and recur for next index
        # `j+1` with one less element `k-1`
        findCombinations(A, k - 1, subarrays, out + (A[j],), j + 1)

if __name__ == ‘__main__’:

A = [1, 2, 3]
k = 2

subarrays = set()
    # process elements from left to right
    findCombinations(A, k, subarrays)
    print(subarrays)
30
Q

Find all distinct combinations of a given length with repetition allowed

Given an integer array, find all distinct combinations of a given length k, where the repetition of elements is allowed.

Input: {1, 2, 3}, k = 2
Output: {1, 1}, {1, 2}, {1, 3}, {2, 2}, {2, 3}, {3, 3}

A

We can use recursion to solve this problem. The idea is to add each array element to the output starting from the last considered element and recur for the remaining elements. To avoid printing permutations, construct each tuple in the same order as array elements. If the combination of size k is found, print it.

The time complexity of the  solution is exponential and requires additional space for the recursion (call stack).
############# code
Solution 1: if array does not contain duplicate. we can add tuple or list as sublists:

Truple *****

def findcombinations(A,k, subarrays,out=(), i=0):
    if len(A)==0 or k>len(A):
        return
    if k==0:
        subarrays.add(out)
        return
    for j in range(i, len(A)):
        findcombinations(A,k-1, subarrays,out+(A[j], ), j)

if __name__ == ‘__main__’:

A = [1, 2, 1]
k = 2

subarrays = set()
    # process elements from left to right
    findcombinations(A, k, subarrays)
    print(subarrays)

List*************

# repetition of elements is allowed
def findCombinations(A, out, k, i, n):
    # base case: if the combination size is `k`, print it
    if len(out) == k:
        print(out)
        return
    # start from the previous element in the current combination
    # till the last element
    for j in range(i, n):
    # add current element `A[j]` to the solution and recur with the
    # same index `j` (as repeated elements are allowed in combinations)
    out.append(A[j])
    findCombinations(A, out, k, j, n)
        # backtrack: remove the current element from the solution
        out.pop()

if __name__ == ‘__main__’:

A = [1, 2, 1]
k = 2

out = []
findCombinations(A, out, k, 0, len(A))

remove duplicate

# repetition of elements is allowed
def findCombinations(A, k, i=0, out=[]):
    # base case: if the combination size is `k`, print it
    if len(out) == k:
        print(out)
        return
    # start from the previous element in the current combination
    # till the last element
    j = i
    while j < len(A):
    # add current element `A[j]` to the solution and recur with the
    # same index `j` (as repeated elements are allowed in combinations)
    out.append(A[j])
    findCombinations(A, k, j, out)
        # backtrack: remove the current element from the solution
        out.pop()
        # code to handle duplicates – skip adjacent duplicates
        while j < len(A) - 1 and A[j] == A[j + 1]:
            j = j + 1
    j = j + 1

if __name__ == ‘__main__’:

A = [1, 2, 1]
k = 2
    # if the list contains repeated elements, sort the list to
    # handle duplicates combinations
    A.sort()
findCombinations(A, k)
31
Q

Find the maximum sequence of continuous 1’s formed by replacing at-most k zeroes by ones
Given a binary array, find the maximum sequence of continuous 1’s that can be formed by replacing at most k zeroes by ones.

For example, consider the following binary array A:

Input: A[] = { 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0 }

For k = 0,
The length of the longest sequence is 4 (from index 6 to 9)

For k = 1,
The length of the longest sequence is 7 (from index 3 to 9)

For k = 2,
The length of the longest sequence is 10 (from index 0 to 9)

For k = 3,
The length of the longest sequence is 11 (from index 0 to 10)

A

We can solve this problem by using the sliding window technique.

we consider two pointer index, left and right both starting from zero. then we traverse the array by right and counting the number of zero till the window gets unstable. window gets unstable if the number of zeros > k. then we move left index to make the window stable. Once the window gets stable we find the length of the window and compare it with the max so far length. we change max sofar if the new window is larger and also save the left index.

O(N)

code

# Function to find the maximum sequence of continuous 1's by replacing
# at most `k` zeroes by 1 using sliding window technique
def findLongestSequence(A, k):
    left = 0        # represents the current window's starting index
    count = 0       # stores the total number of zeros in the current window
    window = 0      # stores the maximum number of continuous 1's found
                    # so far (including `k` zeroes)
leftIndex = 0   # stores the left index of maximum window found so far
    # maintain a window `[left…right]` containing at most `k` zeroes
    for right in range(len(A)):
        # if the current element is 0, increase the count of zeros in the
        # current window by 1
        if A[right] == 0:
            count = count + 1
    # the window becomes unstable if the total number of zeros in it becomes
    # more than `k`
    while count > k:
        # if we have found zero, decrement the number of zeros in the
        # current window by 1
        if A[left] == 0:
            count = count - 1
            # remove elements from the window's left side till the window
            # becomes stable again
            left = left + 1
        # when we reach here, window `[left…right]` contains at most
        # `k` zeroes, and we update max window size and leftmost index
        # of the window
        if right - left + 1 > window:
            window = right - left + 1
            leftIndex = left
    # no sequence found
    if window == 0:
        return
    # print the maximum sequence of continuous 1's
    print("The longest sequence has length", window, "from index",
        leftIndex, "to", (leftIndex + window - 1))

if __name__ == ‘__main__’:

A = [1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0]
k = 2

findLongestSequence(A, k)
32
Q

Find minimum sum subarray of size k
Given an integer array, find the minimum sum subarray of size k, where k is a positive integer.

Input: {10, 4, 2, 5, 6, 3, 8, 1}, k = 3

Output: Minimum sum subarray of size 3 is (1, 3)

A

The problem differs from the problem of finding the minimum sum subsequence of size k. Unlike subsequences, subarrays are required to occupy consecutive positions within the original array.

We can solve this problem by using the sliding window technique. The idea is to maintain a window of size k. For every array element, include it in the window and remove the window’s leftmost element if the window size is more than k. Also maintain the sum of elements in the current window. If the current window sum is more than the minimum found so far, update the minimum sum to the current window sum and store the window’s endpoints.

Note: the difference between this one and the problem of find maximum sequence of ones containing k zeros, is that here the condition which makes the window unstable is on the window size.
so you just need to save the last idx and the for loop will show you the last idx.

O(N)

########################## Code
# Find the minimum sum sublist of a given size `k`
def findSublist(A, k):
    # base case
    if not len(A) or k >= len(A):
        return
    # stores the sum of elements in the current window
    window_sum = 0
    # stores the sum of minimum sum sublist found so far
    min_window = sys.maxsize
    # stores ending index of the minimum sum sublist found so far
    last = 0
for i in range(len(A)):
        # add the current element to the window
        window_sum += A[i]
        # if the window size is more than equal to `k`
        if i + 1 >= k:
            # update the minimum sum window
            if min_window > window_sum:
                min_window = window_sum
                last = i
            # remove a leftmost element from the window
            window_sum -= A[i + 1 - k]
print("The minimum sum sublist is", (last - k + 1, last))

if __name__ == ‘__main__’:

A = [10, 4, 2, 5, 6, 3, 8, 1]
k = 3

findSublist(A, k)
33
Q

Find subarray with given sum

Given an unsorted array of integers, find a subarray that adds to a given number. If there is more than one subarray with the sum of the given number, print any of them.

A

Simple Approach: A simple solution is to consider all subarrays one by one and check the sum of every subarray. Following program implements the simple solution. Run two loops: the outer loop picks a starting point I and the inner loop tries all subarrays starting from i.

Algorithm:

Traverse the array from start to end.
From every index start another loop from i to the end of the array to get all subarray starting from i, keep a variable sum to calculate the sum. For every index in the inner loop update sum = sum + array[j]If the sum is equal to the given sum then print the subarray.
For every index in the inner loop update sum = sum + array[j]
If the sum is equal to the given sum then print the subarray.

O(n2)

The idea is to store the sum of elements of every prefix of the array in a hashmap, i.e, every index stores the sum of elements up to that index hashmap. So to check if there is a subarray with a sum equal to s, check for every index i, and sum up to that index as x. If there is a prefix with a sum equal to x – s, then the subarray with the given sum is found.

Algorithm:

Create a Hashmap (hm) to store a key-value pair, i.e, key = prefix sum and value = its index, and a variable to store the current sum (sum = 0) and the sum of the subarray as s
Traverse through the array from start to end.
For every element update the sum, i.e sum = sum + array[i]
If the sum is equal to s then print that the subarray with the given sum is from 0 to i
If there is any key in the HashMap which is equal to sum – s then print that the subarray with the given sum is from hm[sum – s] to i
Put the sum and index in the hashmap as a key-value pair.

Time complexity: O(N).
If hashing is performed with the help of an array, then this is the time complexity. In case the elements cannot be hashed in an array a hash map can also be used as shown in the above code.
Auxiliary space: O(n).
As a HashMap is needed, this takes linear space.

############## code
def subArraySum(arr, n, Sum):
    # create an empty map
    Map = {}
    # Maintains sum of elements so far
    curr_sum = 0
for i in range(0,n):
        # add current element to curr_sum
        curr_sum = curr_sum + arr[i]
        # if curr_sum is equal to target sum
        # we found a subarray starting from index 0
        # and ending at index i
        if curr_sum == Sum:
        print("Sum found between indexes 0 to", i)
        return
        # If curr_sum - sum already exists in map
        # we have found a subarray with target sum
        if (curr_sum - Sum) in Map:
        print("Sum found between indexes", \
               Map[curr_sum - Sum] + 1, "to", i)

        return

    Map[curr_sum] = i
    # If we reach here, then no subarray exists
    print("No subarray with given sum exists")
# Driver program to test above function
if \_\_name\_\_ == "\_\_main\_\_":
arr = [10, 2, -2, -20, 10]
n = len(arr)
Sum = -10

subArraySum(arr, n, Sum)
34
Q

Smallest subarray with sum greater than a given value

Given an array of integers and a number x, find the smallest subarray with sum greater than the given value.

A

A simple solution is to use two nested loops. The outer loop picks a starting element, the inner loop considers all elements (on right side of current start) as ending element. Whenever sum of elements between current start and end becomes more than the given number, update the result if current length is smaller than the smallest length so far.

Time Complexity: Time complexity of the above approach is clearly O(n2).

Efficient Solution: This problem can be solved in O(n) time using the idea used in this post. Thanks to Ankit and Nitin for suggesting this optimized solution.

def smallest_subarray(A, S, n):
    totall =0
    min_len = len(A)
    for i in range(len(A)):
        totall = A[i]
        if totall > S:
            return 1
        for j in range(i, len(A)):
            totall = totall + A[j]
            if totall == S:
                if min_len > j-i+1:
                    min_len = j-i+1
    return min_len
##############################################
# O(n) solution for finding smallest
# subarray with sum greater than x
# Returns length of smallest subarray
# with sum greater than x. If there
# is no subarray with given sum, then
# returns n + 1
 def smallest_sub(A, S):
    left =0
    min_len = len(A)+1
    totall = 0
for right in range(len(A)):

    totall += A[right]

    while totall > S and left <= right:
        min_len = min(min_len, right-left+1)

        totall -= A[left]

        left += 1
print(min_len) 

##############################

def smallestSubWithSum(arr, n, x):

    # Initialize current sum and minimum length
    curr_sum = 0
    min_len = n + 1
    # Initialize starting and ending indexes
    start = 0
    end = 0
    while (end < n):
    # Keep adding array elements while current
    # sum is smaller than or equal to x
    while (curr_sum <= x and end < n):
        curr_sum += arr[end]
        end += 1
        # If current sum becomes greater than x.
        while (curr_sum > x and start < n):
            # Update minimum length if needed
            if (end - start < min_len):
                min_len = end - start
        # remove starting elements
        curr_sum -= arr[start]
        start += 1

return min_len
# Driver program
arr1 = [1, 4, 45, 6, 10, 19]
x = 51
n1 = len(arr1)
res1 = smallestSubWithSum(arr1, n1, x)
print("Not possible") if (res1 == n1 + 1) else print(res1)
35
Q

Find subarray with given sum with negatives allowed in constant space

Given an unsorted array of integers, find a subarray that adds to a given number. If there is more than one subarray with the sum of the given number, print any of them.

A

an approach without using any extra space is discussed.
The idea is to modify the array to contain only positive elements:

Find the smallest negative element in the array and increase every value in the array by the absolute value of the smallest negative element found.

We may notice that after doing the above modification, the sum of every subarray will also increase by:

(number of elements in the subarray) * (absolute value of min element)
After doing the above modification to the input array, the task is reduced to finding if there is any subarray in the given array of only positive numbers with the new target sum. This can be done using the sliding window technique in O(N) time and constant space.
Every time while adding elements to the window, increment the target sum by the absolute value of the minimum element and, similarly, while removing elements from the current window, decrement the target sum by the absolute value of the minimum element so that for every subarray of length, say K, the updated target sum will be:

targetSum = sum + K*abs(minimum element)

Below is the approach for the same:

Initialize a variable curr_sum as the first element.
The variable curr_sum indicates the sum of the current subarray.
Start from the second element and add all elements one by one to the curr_sum, and keep incrementing the target sum by abs(minimum element).
If curr_sum becomes equal to the target sum, then print the solution.
If curr_sum exceeds the sum, then remove the trailing elements while decreasing curr_sum is greater than the sum and keep decreasing the target sum by abs(minimum element).
########### code
def subArraySum(arr, n, summ):
    minEle = 10**9
    # Find minimum element in the array
    for i in range(n):
        minEle = min(arr[i], minEle)
    # Initialize curr_summ as value of
    # first element and starting point as 0
    curr_summ = arr[0] + abs(minEle)
    start = 0
    # Starting window length will be 1,
    # For generating new target summ,
    # add abs(minEle) to summ only 1 time
    targetSum = summ
    # Add elements one by one to curr_summ
    # and if the curr_summ exceeds the
    # updated summ, then remove starting element
    for i in range(1, n + 1):
    # If curr_summ exceeds the summ,
    # then remove the starting elements
    while (curr_summ - (i - start) * abs(minEle) >
                   targetSum and start < i):
        curr_summ = curr_summ - arr[start] - abs(minEle)
        start += 1

    # If curr_summ becomes equal to summ,
    # then return true
    if (curr_summ - (i - start) *
        abs(minEle) == targetSum):
        print("Sum found between indexes",
                      start, "and", i - 1)
        return
        # Add this element to curr_summ
        if (i < n):
            curr_summ = curr_summ + arr[i] + abs(minEle)
    # If we reach here, then no subarray
    print("No subarray found")
# Driver Code
arr = [10, -12, 2, -2, -20, 10]
n = len(arr)

summ = -10

subArraySum(arr, n, summ)

36
Q

Check if array can be sorted with one swap

Given an array containing N elements. Find if it is possible to sort it in non-decreasing order using atmost one swap.

A
A simple approach is to sort the array and compare the required position of the element and the current position of the element. If there are no mismatches, the array is already sorted. If there are exactly 2 mismatches, we can swap the terms that are not in the position to get the sorted array.
o(nlogn)
 #####  code
# A linear Python 3 program to check
# if array becomes sorted after one swap

def checkSorted(n, arr):

    # Create a sorted copy of
    # original array
    b = []
    for i in range(n):
        b.append(arr[i])
b.sort()
    # Check if 0 or 1 swap required
    # to get the sorted array
    ct = 0
    for i in range(n):
        if arr[i] != b[i]:
            ct += 1
if ct == 0 or ct == 2:
    return True
else:
    return False
# Driver Code       
if \_\_name\_\_ == '\_\_main\_\_':
arr = [1, 5, 3, 4, 2]
n = len(arr)
    if checkSorted(n, arr):
        print("Yes")
else:
    print("No")

__________________________________________________
O(n)
An efficient solution is to check in linear time. Let us consider different cases that may appear after one swap.

We swap adjacent elements. For example {1, 2, 3, 4, 5} becomes {1, 2, 4, 3, 5}
We swap non-adjacent elements. For example {1, 2, 3, 4, 5} becomes {1, 5, 3, 4, 2}
We traverse the given array. For every element, we check if it is smaller than the previous element. We count such occurrences. If the count of such occurrences is more than 2, then we cannot sort the array with one swap. If the count is one, we can find elements to swap (smaller and its previous).
If the count is two, we can find elements to swap (previous of first smaller and second smaller).
After swapping, we again check if array becomes sorted or not. We check this to handle cases like {4, 1, 2, 3}

def checkSorted(n, arr):

    # Find counts and positions of
    # elements that are out of order.
    first, second = 0, 0
    count = 0
for i in range(1, n):
    if arr[i] < arr[i - 1]:
        count += 1

        if first == 0:
            first = i
        else:
            second = i
    # If there are more than two elements
    # which are out of order.
    if count > 2:
        return False
    # If all elements are sorted already
    if count == 0:
        return True
    # Cases like {1, 5, 3, 4, 2}
    # We swap 5 and 2.
    if count == 2:
        (arr[first - 1],
         arr[second]) = (arr[second], 
                         arr[first - 1])
    # Cases like {1, 2, 4, 3, 5}
    elif count == 1:
        (arr[first - 1],
         arr[first]) = (arr[first],
                        arr[first - 1])
    # Now check if array becomes sorted
    # for cases like {4, 1, 2, 3}
    for i in range(1, n):
        if arr[i] < arr[i - 1]:
            return False
return True
# Driver Code
if \_\_name\_\_ == '\_\_main\_\_':
arr = [1, 4, 3, 2]
n = len(arr)
    if checkSorted(n, arr):
        print("Yes")
else:
    print("No")
37
Q

Find a triplet with the given sum in an array

Given an unsorted integer array, find a triplet with a given sum in it.

A

Approach 1:
The idea is to sort the given array in ascending order, and for each element nums[i] in the array, check if the triplet is formed by nums[i] and a pair from subarray nums[i+1…n).

The time complexity of the solution is O(n2) and doesn’t require any extra space.

code##################

def printAllTriplets(nums, target):

    # sort the list in ascending order
    nums.sort()
n = len(nums)
    # check if triplet is formed by nums[i] and a pair from
    # sublist nums[i+1…n)
    for i in range(n - 2):
        # remaining sum
        k = target - nums[i]
        # maintain two indices pointing to endpoints of the
        # sublist nums[i+1…n)
        (low, high) = (i + 1, n - 1)
        # loop if `low` is less than `high`
        while low < high:
            # increment `low` index if the total is less than the remaining sum
            if nums[low] + nums[high] < k:
                low = low + 1
            # decrement `high` index if the total is more than the remaining sum
            elif nums[low] + nums[high] > k:
                high = high - 1
            # triplet with the given sum is found
            else:
                # print the triplet
                print((nums[i], nums[low], nums[high]))
                # increment `low` index and decrement `high` index
                low = low + 1
                high = high - 1
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

Approach 2:
The idea is to insert each array element into a hash table. Then consider all pairs present in the array and check if the remaining sum exists in the map or not. If the remaining sum is seen before and triplet doesn’t overlap with each other, i.e., (i, j, i) or (i, j, j), print the triplet and return.

The time complexity of the solution is O(n2) and requires O(n) extra space, where n is the size of the input.

def isTripletExist(nums, target):

    # create an empty dictionary
    d = {}
    # insert (element, index) pair into the dictionary for each input element
    for i, e in enumerate(nums):
        d[e] = i
    # consider each element except the last element
    for i in range(len(nums) - 1):
        # start from the i'th element until the last element
        for j in range(i + 1, len(nums)):
            # remaining sum
            val = target - (nums[i] + nums[j])
        # if the remaining sum is found, we have found a triplet
        if val in d:
            # if the triplet doesn't overlap, return true
            if d[val] != i and d[val] != j:
                return True
    # return false if triplet doesn't exist
    return False

if __name__ == ‘__main__’:

nums = [2, 7, 4, 0, 9, 5, 1, 3]
target = 6
    if isTripletExist(nums, target):
        print('Triplet exists')
    else:
        print('Triplet doesn\'t exist')
38
Q

Generate random input from an array according to given probabilities

Write an algorithm to generate any one of the given n numbers according to given probabilities.

For example, consider the following integer array and their probabilities. The solution should return 1 with 30% probability, 2 with 10% probability, 3 with 20% probability, and so on for every array element.

A

Algorithm:

Construct a sum array S[] from the given probability array P[], where S[i] holds the sum of all P[j] for 0 <= j <= i.
Generate a random integer from 1 to 100 and check where it lies in S[].
Based on the comparison result, return the corresponding element from the input array.

code

from random import randrange

# Function to generate random nums from a list according to the
# given probabilities
def random(nums, probability):
n = len(nums)
if n != len(probability):
    return -1               # error
    # construct a sum list from the given probabilities
    prob_sum = [None] * n
    # `prob_sum[i]` holds sum of all `probability[j]` for `0 <= j <=i`
    prob_sum[0] = probability[0]
    for i in range(1, n):
        prob_sum[i] = prob_sum[i - 1] + probability[i]
    # generate a random integer from 1 to 100
    # and check where it lies in `prob_sum`
    r = randrange(1, 100)
    # based on the comparison result, return the corresponding
    # element from the input list
if r <= prob_sum[0]:        # handle 0th index separately
    return nums[0]

for i in range(1, n):
    if prob_sum[i - 1] < r <= prob_sum[i]:
        return nums[i]

return -1

if __name__ == ‘__main__’:

    # Input: list of integers and their probabilities
    # Goal: generate `nums[i]` with probability equal to `probability[i]`
nums = [1, 2, 3, 4, 5]
probability = [30, 10, 20, 15, 25]
    # maintain a frequency map to validate the results
    freq = {}
    # make 1000000 calls to the `random()` function and store results in a dictionary
    for i in range(1000000):
        val = random(nums, probability)
        freq[val] = freq.get(val, 0) + 1
    # print the results
    for i in range(len(nums)):
        print(f'{nums[i]} ~ {freq.get(nums[i]) / 10000.0}%')
39
Q

Find the smallest window in an array sorting which will make the entire array sorted

Given an integer array, find the smallest window sorting which will make the entire array sorted in increasing order.

A

We can easily solve this problem in linear time. Following is the complete algorithm:

Traverse array from left to right keeping track of maximum so far and note the last encountered index j which is less than the maximum so far.
Traverse array from right to left keeping track of minimum so far and note the last encountered index i, which is more than the minimum so far.
Finally, sort the array from index i to j.
For example, consider array { 1, 2, 3, 7, 5, 6, 4, 8 }. If we traverse the array from left to right, the last encountered index, which is less than the maximum so far, is 6. Similarly, if we traverse the array from right to left, the last encountered index, which is more than the minimum so far, is 3. So, we need to sort the array from index 3 to 6.

############ Code
import sys
# Function to find the smallest window in a list, sorting which will
# make the entire list sorted
def findSublist(A):
leftIndex = rightIndex = -1
    # traverse from left to right and keep track of maximum so far
    max_so_far = -sys.maxsize
    for i in range(len(A)):
        if max_so_far < A[i]:
            max_so_far = A[i]
        # find the last position that is less than the maximum so far
        if A[i] < max_so_far:
            rightIndex = i
    # traverse from right to left and keep track of the minimum so far
    min_so_far = sys.maxsize
    for i in reversed(range(len(A))):
        if min_so_far > A[i]:
            min_so_far = A[i]
        # find the last position that is more than the minimum so far
        if A[i] > min_so_far:
            leftIndex = i
if leftIndex == -1:
    print("Array is already sorted")
    return

print("Sort list from index", leftIndex, "to", rightIndex)

if __name__ == ‘__main__’:

A = [1, 3, 2, 7, 5, 6, 4, 8]
findSublist(A)
40
Q

Find maximum sum path involving elements of given arrays

Given two sorted arrays of integers, find a maximum sum path involving elements of both arrays whose sum is maximum. We can start from either array, but we can switch between arrays only through its common elements.

A

The idea is simple – calculate the sum between common elements present in both arrays and include the maximum sum in the output. For example, consider the following arrays X and Y having four common elements A, B, C, D:

X[]: [sum_x1 … A … sum_x2 … B … sum_x3 … C … sum_x4 … D … sum_x5]
Y[]: [sum_x1 … A … sum_y2 … B … sum_y3 … C … sum_y4 … D … sum_y5]
Here, sum_xi denotes the sum of elements between two common elements in array X. Similarly, sum_yi denotes the sum of elements between two common elements in array Y. For each pair (sum_xi, sum_yi), include max(sum_xi, sum_yi) in the solution, i.e.,

Result = max(sum_x1, sum_y1) + A + max(sum_x2, sum_y2) + B + max(sum_x3, sum_y3) + C + max(sum_x4, sum_y4) + D + max(sum_x5, sum_y5)

######## code
# Function to find the maximum sum path in two given lists.
# The code is similar to the merge routine of the merge sort algorithm
def findMaxSum(X, Y):
total = sum_x = sum_y = 0

m = len(X)
n = len(Y)
    # `i` and `j` denotes the current index of `X` and `Y`, respectively
    i = j = 0
    # loop till `X` and `Y` are empty
    while i < m and j < n:
    # to handle the duplicate elements in `X`
    while i < m-1 and X[i] == X[i+1]:
        sum_x += X[i]
        i = i + 1

    # to handle the duplicate elements in `Y`
    while j < n-1 and Y[j] == Y[j+1]:
        sum_y += Y[j]
        j = j + 1

    # if the current element of `Y` is less than the current element of `X`
    if Y[j] < X[i]:
        sum_y += Y[j]
        j = j + 1
        # if the current element of `X` is less than the current element of `Y`
        elif X[i] < Y[j]:
            sum_x += X[i]
            i = i + 1
    else:    # if X[i] == Y[j]
        # consider the maximum sum and include the current cell's value
        total += max(sum_x, sum_y) + X[i]
            # move both indices by 1 position
            i = i + 1
            j = j + 1
            # reset both sums
            sum_x = 0
            sum_y = 0
# process the remaining elements of `X` (if any)
while i < m:
    sum_x += X[i]
    i = i + 1

# process the remaining elements of `Y` (if any)
while j < n:
    sum_y += Y[j]
    j = j + 1

total += max(sum_x, sum_y)
return total

if __name__ == ‘__main__’:

X = [3, 6, 7, 8, 10, 12, 15, 18, 100]
Y = [1, 2, 3, 5, 7, 9, 10, 11, 15, 16, 18, 25, 50]

print('The maximum sum is', findMaxSum(X, Y))
41
Q

Ternary Search vs Binary search

In this article, we will implement a ternary search algorithm and compare its performance with binary search algorithm.

A

In Ternary Search, we divide our array into three parts (by taking two mid) and discard two-third of our search space at each iteration. At first look, it seems that ternary search might be faster than binary search as its time complexity on an input containing n items should be O(log3n), which is less than the time complexity of binary search O(log2n). Before analyzing this claim, let’s take a look at its C, Java, and Python implementation first.

code

# Ternary search algorithm to return the position of
# target `x` in a given list `A`
def ternarySearch(A, x):
(left, right) = (0, len(A) - 1)

while left <= right:

    leftMid = left + (right - left) // 3
    rightMid = right - (right - left) // 3
        # leftMid = (2*left + right) // 3
        # rightMid = (left + 2*right) // 3
        if A[leftMid] == x:
            return leftMid
        elif A[rightMid] == x:
            return rightMid
        elif A[leftMid] > x:
            right = leftMid - 1
        elif A[rightMid] < x:
            left = rightMid + 1
        else:
            left = leftMid + 1
            right = rightMid - 1
return -1

if __name__ == ‘__main__’:

A = [2, 5, 6, 8, 9, 10]
key = 6

index = ternarySearch(A, key)

if index != -1:
    print(f'Element found at index {index}')
else:
    print('Element found not in the list')

As we can see, at each iteration, ternary search makes at most 4 comparisons as compared to binary search, which only makes 2 comparisons. So,

Ternary Search complexity analysis

For Binary search – T(n) = 2clog2n + O(1)
For Ternary search – T(n) = 4clog3n + O(1)

By applying simple mathematics, we can establish that the time taken by ternary search is equal to 2.log32 times the time taken binary search algorithm.

Now since 2.log32 > 1, we actually get more comparisons with the ternary search.

Therefore, a ternary search will still give the same asymptotic complexity O(log(n)) search time but adds complexity to the implementation. The same argument is valid for a quaternary search or k–nary search for any other higher order.

42
Q

Interpolation search

Given a sorted integer array and a target, determine if the target exists in the array or not using an interpolation search algorithm. If the target exists in the array, return the index of it.

A

We know that binary search always chooses the middle of the remaining search space, discarding one half or the other depending on the comparison result between the mid-value and the target value. The remaining search space is reduced to the part before or after the mid-position.

By comparison, at each search step, Interpolation search calculates wherein the remaining search space the target might be present, based on the low and high values of the search space and the target’s value. The value found at this estimated position is then compared to the target value. If it’s not equal, then the remaining search space is reduced to the part before or after the estimated position depending on the comparison. This method will only work if calculations on the size of differences between target values are sensible.

Interpolation search uses the following formula to calculate the mid-position where A[low…high] is our search space, and target is the given target:

mid = low + ((target – A[low]) * (high – low) / (A[high] – A[low]));

Each iteration of the above code requires between five and six comparisons. On average, the interpolation search makes about log(log(n)) comparisons if the elements are uniformly distributed, where n is the total number of elements to be searched. In the worst case, it can make up to O(n) comparisons. The worst-case might happen when the numerical values of the targets increase exponentially.

https://www.techiedelight.com/interpolation-search/
##### code#####
# Function to determine if target exists in the sorted list `A` or not
# using an interpolation search algorithm
def interpolationSearch(A, target):
    # base case
    if not A:
        return -1
    # search space is A[left…right]
    (left, right) = (0, len(A) - 1)
while A[right] != A[left] and A[left] <= target <= A[right]:
        # estimate mid
        mid = left + (target - A[left]) * (right - left) // (A[right] - A[left])
        # key is found
        if target == A[mid]:
            return mid
        # discard all elements in the right search space, including the middle element
        elif target < A[mid]:
            right = mid - 1
        # discard all elements in the left search space, including the middle element
        else:
            left = mid + 1
    # if the key is found
    if target == A[left]:
        return left
    # target doesn't exist in the list
    return -1

if __name__ == ‘__main__’:

A = [2, 5, 6, 8, 9, 10]
key = 5

index = interpolationSearch(A, key)

if index != -1:
    print('Element found at index', index)
else:
    print('Element found not in the list')
43
Q

mid for interpolation search

A

mid = low + ((target – A[low]) * (high – low) / (A[high] – A[low]));

44
Q

Exponential search

Given a sorted array of n integers and a target value, determine if the target exists in the array or not in logarithmic time. If the target exists in the array, return the index of it.

A

Exponential search is an algorithm used for searching sorted, unbounded/infinite arrays. The idea is to determine a range that the target value resides in and perform a binary search within that range. Assuming that the array is sorted in ascending order, it looks for the first exponent, k, where the value 2k is greater than the search key. Now 2k and 2k-1 becomes the upper bound and lower bound for the binary search algorithm, respectively.

The exponential search takes O(log(i)) time, where i is the target’s position in the array when the target is in the array or position where the target should be if it isn’t in the array.

https://www.techiedelight.com/exponential-search/
###### code
# Binary search algorithm to return the position of key `x` in sublist A[left…right]
def binarySearch(A, left, right, x):
    # base condition (search space is exhausted)
    if left > right:
        return -1
    # find the mid-value in the search space and
    # compares it with the key
mid = (left + right) // 2
    # overflow can happen. Use below
    # mid = left + (right - left) // 2
    # base condition (a key is found)
    if x == A[mid]:
        return mid
    # discard all elements in the right search space,
    # including the middle element
    elif x < A[mid]:
        return binarySearch(A, left, mid - 1, x)
    # discard all elements in the left search space,
    # including the middle element
    else:
        return binarySearch(A, mid + 1, right, x)
# Returns the position of key `x` in a given list `A` of length `n`
def exponentialSearch(A, x):
    # base case
    if not A:
        return -1
bound = 1

# find the range in which key `x` would reside
while bound < len(A) and A[bound] < x:
    bound *= 2        # calculate the next power of 2
    # call binary search on A[bound/2 … min(bound, n-1)]
    return binarySearch(A, bound // 2, min(bound, len(A) - 1), x)
# Exponential search algorithm
if \_\_name\_\_ == '\_\_main\_\_':
A = [2, 5, 6, 8, 9, 10]
key = 9

index = exponentialSearch(A, key)

if index != -1:
    print('Element found at index', index)
else:
    print('Element found not in the list')
45
Q

When exponential search out-performe binary search?

what is while statement for exponential search?

A

exponential search to search in bounded arrays. It can even out-perform binary search when the target is near the beginning of the array. This is because the exponential search will run in O(log(i)) time, where i is the index of the element being searched for in the array, whereas binary search would run in O(log(n)) time, where n is the total number of elements in the array.

while Arr[bound] < target and bound < bound < len(Arr)

46
Q

Median of two sorted arrays of same size

There are 2 sorted arrays A and B of size n each. Write an algorithm to find the median of the array obtained after merging the above 2 arrays(i.e. array of length 2n). The complexity should be O(log(n)).

A

write a general function for calculation median of one array 2) find a getMedian(ar1, ar2, n):
1) consider the case where n==0 –> retur -1
2) consider the case where n=1 –> return (ar1[0]+arr2[0]/2)
3) consider the case where n ==2 –> return (max(arr1[0] , arr2[0])+min(arr1[1], arr2[1])/2)
4) else: find mdian of arr1 and arr2
1) Calculate the medians m1 and m2 of the input arrays ar1[]
and ar2[] respectively. 2) If m1 and m2 both are equal then we are done. return m1 (or m2)
3) If m1 is greater than m2, then median is present in one of the below two subarrays.
a) From first element of ar1 to m1 (ar1[0…|n/2|])
b) From m2 to last element of ar2 (ar2[|n/2|…n-1])
4) If m2 is greater than m1, then median is present in one
of the below two subarrays. a) From m1 to last element of ar1 (ar1[|n/2|…n-1]) b) From first element of ar2 to m2 (ar2[0…|n/2|])
5) Repeat the above process until size of both the subarrays becomes 2.
6) If size of the two arrays is 2 then use below formula to get the median. Median = (max(ar1[0], ar2[0]) + min(ar1[1], ar2[1]))/2

Code#############

def median(arr, n):
    if n % 2==0:
        return ( arr[(n)//2]+arr[(n-1)//2]//2)
    else:
        return arr[n//2]
def GetMedian(arr1, arr2, n):
    if n==0:
        return -1
    elif n==1:
        return (arr1[0]+arr2[0]/2)
elif n==2:
    return (max(arr1[0],arr2[0])+min(arr1[1], arr2[1]))/2

else:
    m1 = median(arr1, n)
    m2 = median(arr2, n)

    if m1>m2:
        if n%2==0:
            return GetMedian(arr1[:int(n/2)+1], arr2[int(n/2)-1:], int(n//2)+1)
            else:
                return GetMedian(arr1[:int(n/2)+1], arr2[int(n/2):], (n//2)+1)
    else:
        if n%2==0:
            return GetMedian(arr2[:int(n/2)+1], arr1[int(n/2)-1:], n//2+1)
        else:
            return GetMedian(arr1[:int(n/2)+1], arr2[int(n/2):], n//2+1)
# Driver code
arr1 = [1, 2, 3, 6]
arr2 = [4, 6, 8, 10]
n = len(arr1)
# print(int(GetMedian(arr1,arr2,n)))
# This code is contributed by
# baby_gog9800
GetMedian(arr1,arr2,n)
47
Q

String To Integer

Implement the myAtoi(string s) function, which converts a string to a 32-bit signed integer (similar to C/C++’s atoi function).

The algorithm for myAtoi(string s) is as follows:

Read in and ignore any leading whitespace.
Check if the next character (if not already at the end of the string) is ‘-‘ or ‘+’. Read this character in if it is either. This determines if the final result is negative or positive respectively. Assume the result is positive if neither is present.
Read in next the characters until the next non-digit character or the end of the input is reached. The rest of the string is ignored.
Convert these digits into an integer (i.e. “123” -> 123, “0032” -> 32). If no digits were read, then the integer is 0. Change the sign as necessary (from step 2).
If the integer is out of the 32-bit signed integer range [-231, 231 - 1], then clamp the integer so that it remains in the range. Specifically, integers less than -231 should be clamped to -231, and integers greater than 231 - 1 should be clamped to 231 - 1.
Return the integer as the final result.

A

Algorithm

1) Initialize two variables:
sign (to store the sign of the final result) as 1.
result (to store the 32-bit integer result) as 0.

2)
Skip all leading whitespaces in the input string.

3)
Check if the current character is a ‘+’ or ‘-‘ sign:
If there is no symbol or the current character is ‘+’, keep sign equal to 1.
Otherwise, if the current character is ‘-‘, change sign to -1.
4)
Iterate over the characters in the string as long as the current character represents a digit or until we reach the end of the input string.
Before appending the currently selected digit, check if the 32-bit signed integer range is violated. If it is violated, then return INT_MAX or INT_MIN as appropriate.
Otherwise, if appending the digit does not result in overflow/underflow, append the current digit to the result.

5) Return the final result with its respective sign, sign * result.

O(N)
O(1)

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_ CODE\_\_\_\_\_\_\_\_
def String_to_integer(s):
sign = 1
result = 0

INT_MAX_ = 2**31 -1
INT_MIN_ = -2**31

n = len(s)
index = 0

while index <=n and s[index] == " ":
    index +=1
    if s[index] =="+":
        sign = 1
        index +=1
    elif s[index] =="-":
        sign = -1
        index+=1
    while index < n and s[index].isdigit():
        digit = int(s[index])
    if (result > INT_MAX_//10 ) or (result == INT_MAX_ //10) and (digit >INT_MAX_ %10):
        return INT_MAX_ if sign ==1 else INT_MIN_

    result = 10 * result + digit
    index += 1

return sign * result
48
Q

Median of two sorted array with different length

A

variabals fro algorithm:

define 2 variables:

min_index = 0
max_index = n ----- > len(smaller array)

to partition array A: (min_index + max_inde)/2 ----> call it  i --> i is the number of elements to be inserted to the first half 

to partiotion array B: (m+n+1)/2 -i ---- > call it j ---> number of elements to be insterted to the first half from array B

Edge cases are:

if length of array A is 0, i ==0, return median of B

elif  if length of array 2 is 0, j==0, return median of A. 

else max(A[i-1],B[j-1])

Algoithm:
consider n < m .

while min_index <= max_index:

       # make i, j
        i= (min_index + max_index)/2
        j = (m+n+1)/2 - i

        if i < n and j>0 and b[j-1] > a[i] :
            min_index += 1

        elif i > 0 and j < m  and   b[] < a[i-1] :
            max_index = i-1

         else:
             if (i ==0):
                 return b[j-1]

             if j==0:
                 return a[j-1]
                  else:
                      return  max(a[i-1], b[j-1])

_____________ code_________

49
Q

You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]).

Find two lines that together with the x-axis form a container, such that the container contains the most water.

Return the maximum amount of water a container can store.

A

The intuition behind this approach is that the area formed between the lines will always be limited by the height of the shorter line. Further, the farther the lines, the more will be the area obtained.

We take two pointers, one at the beginning and one at the end of the array constituting the length of the lines. Futher, we maintain a variable \text{maxarea}maxarea to store the maximum area obtained till now. At every step, we find out the area formed between them, update \text{maxarea}maxarea and move the pointer pointing to the shorter line towards the other end by one step.

\_\_\_\_\_\_\_\_\_\_\_\_\_ code\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
def max_area2(arr):
    left = 0
    right = len(arr)-1
    first = -1
    second = -1
    max_area = float("-inf")
    area = 0
    while left <=right:
        width = right-left
        area = (width)*(min(arr[right],arr[left]))
    if max_area < area:
        max_area  = area
        first = left
        second = right
        if arr[left] <= arr[right]:
            left+=1
        else:
            right = right-1
    print(first,second)
    print(arr[first],arr[second])
    return max_area

arr = [1,8,6,2,5,4,8,3,7]
max_area2(arr)

50
Q

Find pairs with difference k in an array whith duplicat

A
Sort A
mak a set
while i < size while i+1< len(A) and A[i]==A[i+1]:
  i +=1
if A[i] - k in set
  print(A[i], A[i]-k)
if A[i] + k in set
  print(A[i], A[i]+k)

NlogN

______________________

def find_pairs_diff(A, diff):
    A.sort()
s = set()

i =0
while i
51
Q

Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.
array has not repitation

A

O(n2) for both using hash map, and sorted list.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
def threeSum( nums):
        result =set()
        sorted_nums = sorted(nums)
    for k in range(len(sorted_nums)-1):
        target = -sorted_nums[k]
        i = k+1
        j = len(sorted_nums)-1

        while i target:
                j -=1
                else:
                    result.add((a,b,-target))
                    i += 1
                    j -=1
        return result
51
Q

Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0. with repetiosn

A

For the main function:

Sort the input array nums.
Iterate through the array:
If the current value is greater than zero, break from the loop. Remaining values cannot sum to zero.
If the current value is the same as the one before, skip it.
Otherwise, call twoSumII for the current position i.
For twoSumII function:

Set the low pointer lo to i + 1, and high pointer hi to the last index.
While low pointer is smaller than high:
If sum of nums[i] + nums[lo] + nums[hi] is less than zero, increment lo.
If sum is greater than zero, decrement hi.
Otherwise, we found a triplet:
Add it to the result res.
Decrement hi and increment lo.
Increment lo while the next value is the same as before to avoid duplicates in the result.

O(n2)
_____________________

def threeSum(self, nums: List[int]) -> List[List[int]]:
    res = []
    nums.sort()
    for i in range(len(nums)):
        if nums[i] > 0:
            break
        if i == 0 or nums[i - 1] != nums[i]:
            self.twoSumII(nums, i, res)
    return res

def twoSumII(self, nums: List[int], i: int, res: List[List[int]]):
    lo, hi = i + 1, len(nums) - 1
    while (lo < hi):
        sum = nums[i] + nums[lo] + nums[hi]
        if sum < 0:
            lo += 1
        elif sum > 0:
            hi -= 1
        else:
            res.append([nums[i], nums[lo], nums[hi]])
            lo += 1
            hi -= 1
            while lo < hi and nums[lo] == nums[lo - 1]:
                lo += 1
52
Q

Given an integer array nums of length n and an integer target, find three integers in nums such that the sum is closest to target.

Return the sum of the three integers.

You may assume that each input would have exactly one solution.

A

Initialize the minimum difference diff with a large value. Sort the input array nums.
Iterate through the array:
For the current position i, set lo to i + 1, and hi to the last index. While the lo pointer is smaller than hi:
Set sum to nums[i] + nums[lo] + nums[hi]. If the absolute difference between sum and target is smaller than the absolute value of diff: Set diff to target - sum.
If sum is less than target, increment lo. Else, decrement hi.
If diff is zero, break from the loop.
Return the value of the closest triplet, which is target - diff.

O(n2)
################### code
def threeSumClosest(self, nums: List[int], target: int) -> int:
        diff = float('inf')
        nums.sort()
        for i in range(len(nums)):
            lo, hi = i + 1, len(nums) - 1
            while (lo < hi):
                sum = nums[i] + nums[lo] + nums[hi]
                if abs(target - sum) < abs(diff):
                    diff = target - sum
                if sum < target:
                    lo += 1
                else:
                    hi -= 1
            if diff == 0:
                break
        return target - diff
53
Q

3 sum Smaller
Given an array of n integers nums and an integer target, find the number of index triplets i, j, k with 0 <= i < j < k < n that satisfy the condition nums[i] + nums[j] + nums[k] < target.

A

def threeSumSmaller(nums, target):

    nums.sort()
    count =0 
    for i in range(len(nums)-1):
        low = i+1
        high = len(nums)-1
        while low < high:
            sum_ = nums[low]+nums[high]+nums[i]
            if sum_ < target:
                count += high-low
                low +=1
            else:
                high -=1
    return count