Lecture 2 : Medium Problems on arrays¶
Find the Majority Element that occurs more than N/2 times¶
Example 1:
Input Format: N = 3, nums[] = {3,2,3}
Result: 3
Example 2:
Input Format: N = 7, nums[] = {2,2,1,1,1,2,2}
Result: 2
Example 3:
Input Format: N = 10, nums[] = {4,4,2,4,3,4,4,3,2,4}
Result: 4
Approach 1 ( Use count map)¶
from collections import Counter
def majority_element(nums):
count_map = Counter(nums)
result , max_count = nums[0],1
for num,count in count_map.items():
if count > max_count:
max_count = count
result = num
return result
print(majority_element([3,2,3]))
print(majority_element([2,2,1,1,1,2,2]))
print(majority_element([4,4,2,4,3,4,4,3,2,4]))
3 2 4
Complexity¶
O(N) : N = len(nums)
O(N) : N = len(nums)
Approach 2 (Moore's Voting Algorithm)¶
Keep track of count
When count reaches 0 , switch element
def majority_element(nums):
count , result = 1,nums[0]
n = len(nums)
for i in range(1,n):
if nums[i] == result:
count +=1
else:
count -=1
if count ==0:
count =1
result = nums[i]
return result
print(majority_element([3,2,3]))
print(majority_element([2,2,1,1,1,2,2]))
print(majority_element([4,4,2,4,3,4,4,3,2,4]))
3 2 4
Complexity¶
O(N) : N = len(nums)
O(1)
Kadane's Algorithm : Maximum Subarray Sum in an Array¶
Input: arr = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Input: arr = [1]
Output: 1
Approach 1 (Brute Force)¶
- We will take 3 loops
- i : 0 -> n-1
- j : 0 -> n-1
- result = max(sum9i,j)
import sys
def max_subarray(nums):
n = len(nums)
result = -sys.maxsize -1
for i in range(n):
for j in range(i,n):
sum =0
for k in range(i,j+1):
sum += nums[k]
result = max(result,sum)
return result
print(max_subarray([-2,1,-3,4,-1,2,1,-5,4]))
print(max_subarray([1]))
6 1
Complexity¶
O(N ^3) : N = len(nums)
O(1)
Approach 2¶
- Get rid of extra loop k
- instead of
for k in range(i,j+1):
sum += nums[k]
- use
sum += nums[j]
import sys
def max_subarray(nums):
n = len(nums)
result = -sys.maxsize -1
for i in range(n):
sum =0
for j in range(i,n):
sum += nums[j]
result = max(result,sum)
return result
print(max_subarray([-2,1,-3,4,-1,2,1,-5,4]))
print(max_subarray([1]))
6 1
Complexity¶
O(N^2) : N = len(nums)
O(1)
Approach 3 (Kadan's algo)¶
- Move the sum outside all loops
- Any time sum is < 0 , sum =0 and dont include it in the subarray
import sys
def max_subarray(nums):
n = len(nums)
result = -sys.maxsize -1
sum =0
for i in range(n):
sum += nums[i]
if sum > result:
result = sum
if sum < 0 :
sum =0
return result
print(max_subarray([-2,1,-3,4,-1,2,1,-5,4]))
print(max_subarray([1]))
6 1
Complexity¶
O(N) : N = len(nums)
O(1)
Stock Buy And Sell¶
Input: prices = [7,1,5,3,6,4]
Output: 5
Input: prices = [7,6,4,3,1]
Output: 0
Approach 1 (Brute Force)¶
Buy at each day and calculate profit and find max
def max_profit(prices):
n = len(prices)
result =0
for i in range(n):
profit =0
for j in range(i+1,n):
profit = prices[j] - prices[i]
result = max(profit,result)
return result
print(max_profit([7,1,5,3,6,4]))
print(max_profit([7,6,4,3,1]))
5 0
Complexity¶
O(N^2): N = len(prices)
O(1)
Approach 2¶
- calculate min_buy price
- calculate max_profit
def max_profit(prices):
n = len(prices)
min_price , result = prices[0],0
for i in range(1,n):
profit = prices[i] - min_price
result = max(profit,result)
min_price = min(min_price,prices[i])
return result
print(max_profit([7,1,5,3,6,4]))
print(max_profit([7,6,4,3,1]))
5 0
Complexity¶
O(N) : N= len(prices)
O(1)
Leaders in an array¶
Problem Statement: Given an array, print all the elements which are leaders. A Leader is an element that is greater than all of the elements on its right side in the array.
arr = [4, 7, 1, 0]
7 1 0
arr = [10, 22, 12, 3, 0, 6]
22 12 6
Approach 1 (Brute Force)¶
- check_leader
- run check_leader for each element
def leaders_array(nums):
n = len(nums)
result = [nums[n-1]]
def check_leader(i):
for j in range(i+1,n):
if nums[j] > nums[i]:
return False
return True
for i in range(n-2,-1,-1):
if check_leader(i):
result.append(nums[i])
return result
print(leaders_array([4, 7, 1, 0]))
print(leaders_array([10, 22, 12, 3, 0, 6]))
[0, 1, 7] [6, 12, 22]
Complexity¶
O(N ^2) : N = len(nums)
O(1)
Approach 2¶
- move backwards
- leep track of max till that point
def leaders_array(nums):
n = len(nums)
result = [nums[n-1]]
max_val = nums[n-1]
for i in range(n-2,-1,-1):
if nums[i] > max_val:
result.append(nums[i])
max_val = nums[i]
return result
print(leaders_array([4, 7, 1, 0]))
print(leaders_array([10, 22, 12, 3, 0, 6]))
[0, 1, 7] [6, 12, 22]
Complexity¶
O(N)
O(1)
Longest Consecutive Sequence in an Array¶
Input: [100, 200, 1, 3, 2, 4]
Output: 4
Input: [3, 8, 5, 7, 6]
Output: 4
Approach 1¶
- linear search for each sequence
- max of each count = result
def longest_consecutive_length(nums):
def linear_search(target):
for num in nums:
if num == target:
return True
return False
n = len(nums)
result =1
for i in range(n):
count =1
val = nums[i]
while linear_search(val +1):
count +=1
val +=1
result = max(result,count)
return result
print(longest_consecutive_length([100, 200, 1, 3, 2, 4]))
print(longest_consecutive_length([3, 8, 5, 7, 6]))
4 4
Complexity¶
O(N^2) : N = len(nums)
O(1)
Approach 2¶
- create a set of nums for O(1) lookup
- only start from beg from sequence
- keep track of count
- result = max(count)
def longest_consecutive_length(nums):
nums_set = set(nums)
result =0
for num in nums:
# start of sequence
if num -1 not in nums_set:
count =1
val = num
while val + 1 in nums_set:
count+=1
val +=1
result = max(count,result)
return result
print(longest_consecutive_length([100, 200, 1, 3, 2, 4]))
print(longest_consecutive_length([3, 8, 5, 7, 6]))
4 4
Complexity¶
O(N) : N = len(nums) because each element is only accessed twice
O(N) : N = len(nums) becuase of set
Count Subarray sum Equals K¶
Given an array of integers and an integer k, return the total number of subarrays whose sum equals k. must be contiguius nums can be negative
Input Format: N = 4, array[] = {3, 1, 2, 4}, k = 6
Result: 2
Input Format: N = 3, array[] = {1,2,3}, k = 3
Result: 2
Approach 1 Brute Force¶
- find the sum from each index , as soon as it becomes k , increment the count
def count_sub_array(nums,k):
count =0
n = len(nums)
for i in range(n):
sum = nums[i]
if sum ==k:
count +=1
for j in range(i+1,n):
sum += nums[j]
if sum ==k:
count +=1
return count
print(count_sub_array([3,1,2,4],6))
print(count_sub_array([1,2,3],3))
2 2
Make it cleaner and remove duplicate¶
def count_sub_array(nums,k):
count =0
n = len(nums)
for i in range(n):
sum =0
for j in range(i,n):
sum += nums[j]
if sum ==k:
count +=1
return count
print(count_sub_array([3,1,2,4],6))
print(count_sub_array([1,2,3],3))
2 2
Complexity¶
- O(N^2) : N = len(nums)
- O(1)
Approach 2 (Use prefix sum)¶
instead of traversing the whole array every time
we will store the prefix_sum in in map
prefix_sum = sum of all the elements till that index(including)
if prefix_sum[i] - prefix_sum[j] = k , then subarray from index j+1 to i has sum k
def count_sub_array(nums,k):
count =0
prefix_sum =0
prefix_count = {0 : 1}
for num in nums:
prefix_sum += num
if prefix_sum - k in prefix_count:
count += prefix_count[prefix_sum -k]
prefix_count[prefix_sum] = prefix_count.get(prefix_sum,0)+1
return count
print(count_sub_array([3,1,2,4],6))
print(count_sub_array([1,2,3],3))
2 2
Complexity¶
- O(N) : N = len(nums)
- O(N) : N = len(nums)