Step 3 Lecture 1 : Solve problems on arrays easy¶
Find the Largest element in an array¶
Example 1:
Input: arr[] = {2,5,1,3,0};
Output: 5
Explanation: 5 is the largest element in the array.
Example2:
Input: arr[] = {8,10,5,7,9};
Output: 10
Explanation: 10 is the largest element in the array.
Approach 1 (Brute force - Iterative)¶
def largest_element(nums):
large = nums[0]
for num in nums:
large = max(large,num)
return large
print(largest_element([2,5,1,3,0]))
print(largest_element([8,10,5,7,9]))
5 10
complexity¶
O(N) : N = len(nums)
O(1)
Approach 2 (Brute force - recursive)¶
large(i) = max(large(i-1),nums[i-1])
large(1) = nums[0]
def largest_element(nums):
n = len(nums)
def large(n):
if n==1:
return nums[0]
return max(nums[n-1],large(n-1))
return large(n)
print(largest_element([2,5,1,3,0]))
print(largest_element([8,10,5,7,9]))
5 10
complexity¶
O(N) : N = len(nums)
O(N) : N = len(nums)
Find Second Smallest and Second Largest Element in an array¶
Example 1:
Input: [1,2,4,7,7,5]
Output: Second Smallest : 2
Second Largest : 5
Explanation: The elements are as follows 1,2,3,5,7,7 and hence second largest of these is 5 and second smallest is 2
Example 2:
Input: [1]
Output: Second Smallest : -1
Second Largest : -1
Explanation: Since there is only one element in the array, it is the largest and smallest element present in the array. There is no second largest or second smallest element present.
Approach 1 (Sorting)¶
- This approach only works if the element does not have duplicates
def second_elements(nums):
sorted_nums = sorted(nums)
n = len(nums)
return sorted_nums[1],sorted_nums[n-2]
print(second_elements([1,2,9,7,5]))
(2, 7)
complexity¶
O(N log N ) : N = len(nums)
O(1)
Approach 2 (Two pass)¶
- first pass : find the largest
- second pass : find the second
this works even with duplicates
def second_elements(nums):
smallest,largest = nums[0],nums[0]
# first pass
for num in nums:
smallest = min(smallest,num)
largest = max(largest,num)
# second pass
small,large = nums[0],nums[0]
for num in nums:
if num > smallest and num < small:
small = num
if num < largest and num > large:
large = num
return small,large
print(second_elements([1,2,4,7,7,5]))
(1, 5)
Complexity¶
O(N) : N = len(nums)
O(1)
Approach 3 ( Single Pass)¶
- implement them separately
- second_smallest
- second_largest
def second_small(nums):
smallest,small = float("inf"),float("inf")
for num in nums:
if num < smallest:
smallest = num
elif num > smallest and num < small:
small = num
return small
def second_large(nums):
largest,large = -float("inf"),-float("inf")
for num in nums:
if num > largest:
largest = num
elif num < largest and num > large:
large = num
return large
print(second_small([1,2,4,7,7,5]))
print(second_large([1,2,4,7,7,5]))
2 5
Complexity¶
O(N) : N = len(nums)
O(1)
Check if an Array is Sorted¶
Given an array of size n, write a program to check if the given array is sorted in (ascending / Increasing / Non-decreasing) order or not. If the array is sorted then return True, Else return False.
{1,2,3,4,5}
True
{5,4,6,7,8}
False
Approach 1 (Brute Force)¶
- forward pass
def is_sorted(nums):
n = len(nums)
for i in range(1,n):
if nums[i] < nums[i-1]:
return False
return True
print(is_sorted([1,2,3,4,5]))
print(is_sorted([5,4,6,7,8]))
True False
Complexity¶
O(N) : N = len(nums)
O(1)
Check if the array is rotated sorted¶
[3,4,5,1,2]
True
[2,1,3,4]
False
[1,2,3]
True
Approach 1¶
- next_index(i) = (i+1) %n
- if rotation breaks more than 1 times ,then unsorted
e.g. [3,4,5,1,2] only 1 break i.e. 5 -> 1
def is_rotated(nums):
n = len(nums)
count =0
for i in range(n):
next_idx = (i+1) % n
if nums[i]>nums[next_idx]:
count +=1
return count <2
print(is_rotated([3,4,5,1,2]))
print(is_rotated([2,1,3,4]))
print(is_rotated([1,2,3]))
True False True
Complexity¶
O(N) : N= len(nums)
O(1)
Remove Duplicates in-place from Sorted Array¶
Example 1:
Input: arr[1,1,2,2,2,3,3]
Output: arr[1,2,3,_,_,_,_]
Explanation: Total number of unique elements are 3, i.e[1,2,3] and Therefore return 3 after assigning [1,2,3] in the beginning of the array.
Example 2:
Input: arr[1,1,1,2,2,3,3,3,3,4,4]
Output: arr[1,2,3,4,_,_,_,_,_,_,_]
Explanation: Total number of unique elements are 4, i.e[1,2,3,4] and Therefore return 4 after assigning [1,2,3,4] in the beginning of the array.
Approach 1 (Forward Pass with 2 ptrs)¶
left cursor = 0
right = 1 -> n-1
once nums[left] < nums[right] : left and right are relative correct
swap (left+1 , right)
if right = left +1 , swap(left+1, right) = swap(left+1, left+1) => unchanged
def remove_duplicates_sorted(nums):
left =0
n = len(nums)
for right in range(1 ,n):
if nums[left] < nums[right]:
nums[right],nums[left+1] = nums[left+1],nums[right]
left +=1
return nums
print(remove_duplicates_sorted([1,1,2,2,2,3,3]))
print(remove_duplicates_sorted([1,1,1,2,2,3,3,3,3,4,4]))
[1, 2, 3, 2, 2, 1, 3] [1, 2, 3, 4, 2, 1, 3, 3, 3, 1, 4]
complexity¶
O(N) : N = len(nums)
O(1)
Left Rotate the Array by One¶
Example 1:
Input: N = 5, array[] = {1,2,3,4,5}
Output: 2,3,4,5,1
Example 2:
Input: N = 1, array[] = {3}
Output: 3
approach 1¶
- save the first element
- nums[i] = nums[i+1]
- nums[end] = saved element
def rotate_left(nums):
n = len(nums)
if n==1:
return nums
first = nums[0]
for i in range(0,n-1):
nums[i] = nums[i+1]
nums[n-1] = first
return nums
print(rotate_left([1,2,3,4,5]))
print(rotate_left([3]))
[2, 3, 4, 5, 1] [3]
Complexity¶
O(N) : N= len(nums)
O(1)
Rotate array by K elements¶
Example 1:
Input: N = 7, array[] = {1,2,3,4,5,6,7} , k=2 , right
Output: 6 7 1 2 3 4 5
Example 2:
Input: N = 6, array[] = {3,7,8,9,10,11} , k=3 , left
Output: 9 10 11 3 7 8
Approach 1 (Extra array duplication)¶
- decrease k = k & n
- result[i] = nums[(i-k)%n]
def rotate_k(nums,k):
n = len(nums)
result = [0] * n
k = k %n
for i in range(n):
result[i] = nums[i-k]
return result
print(rotate_k([1,2,3,4,5,6,7],2))
print(rotate_k([3,7,8,9,10,11],3))
[6, 7, 1, 2, 3, 4, 5] [9, 10, 11, 3, 7, 8]
Complexity¶
O(N) : N = len(nums)
O(N) : N = len(nums)
Approach 2 (Use tripple reversal method)¶
- reverse n elements
- reverse first k elements
- reverse last n-k elements
e.g.
- 1,2,3,4,5,6,7
- 7,6,5,4,3,2,1 (reverse n elements)
- 6,7,5,4,3,2,1 (reverse first k elements )
- 6,7,1,2,3,4,5 (revese last n-k elements)
def rotate_k(nums,k):
def reverse(left,right):
while left < right:
nums[left],nums[right] = nums[right],nums[left]
left +=1
right -=1
n = len(nums)
k = k %n
reverse(0,n-1)
reverse(0,k-1)
reverse(k,n-1)
return nums
print(rotate_k([1,2,3,4,5,6,7],2))
print(rotate_k([3,7,8,9,10,11],3))
[6, 7, 1, 2, 3, 4, 5] [9, 10, 11, 3, 7, 8]
Complexity¶
O(N) : N = len(nums)
O(1)
Move all Zeros to the end of the array¶
Input: 1 ,0 ,2 ,3 ,0 ,4 ,0 ,1
Output: 1 ,2 ,3 ,4 ,1 ,0 ,0 ,0
Input: 1,2,0,1,0,4,0
Output: 1,2,1,4,0,0,0
Approach 1 (Relative order will not be preserved)¶
- left and right ptr
- swap when found
def move_zeros(nums):
n = len(nums)
left =0
right = n-1
while left < right:
if nums[left] !=0:
left +=1
elif nums[right] ==0:
right -=1
else:
nums[left],nums[right] = nums[right],nums[left]
left +=1
right -=1
return nums
print(move_zeros([1 ,0 ,2 ,3 ,0 ,4 ,0 ,1]))
print(move_zeros([1,2,0,1,0,4,0]))
[1, 1, 2, 3, 4, 0, 0, 0] [1, 2, 4, 1, 0, 0, 0]
Approach 2 (Preserve the relative order)¶
def move_zeros(nums):
n = len(nums)
write_pos = 0
for i in range(n):
if nums[i] !=0:
nums[i],nums[write_pos] = nums[write_pos],nums[i]
write_pos +=1
return nums
print(move_zeros([1 ,0 ,2 ,3 ,0 ,4 ,0 ,1]))
print(move_zeros([1,2,0,1,0,4,0]))
[1, 2, 3, 4, 1, 0, 0, 0] [1, 2, 1, 4, 0, 0, 0]
Complexity¶
O(N) : N = len(nums)
O(1)
Linear Search¶
Input: arr[]= 1 2 3 4 5, num = 3
Output: 2
Input: arr[]= 5 4 3 2 1, num = 5
Output: 0
def linear_search(nums,target):
for i in range(len(nums)):
if nums[i] == target:
return i
print(linear_search([1,2,3,4,5],3))
print(linear_search([5,4,3,2,1],5))
2 0
Complexity¶
O(N) : N = len(nums)
O(1)
Find the missing number in an array¶
Given an integer N and an array of size N-1 containing N-1 numbers between 1 to N. Find the number(between 1 to N), that is not present in the given array.
Input Format: N = 5, array[] = {1,2,4,5}
Result: 3
Input Format: N = 3, array[] = {1,3}
Result: 2
Approach1 (Brute Force)¶
- linear search every element
def missing_num(nums):
n = len(nums)
def linear_search(target):
for num in nums:
if num == target:
return True
return False
for i in range(1,n+2):
if not linear_search(i):
return i
print(missing_num([1,2,4,5]))
print(missing_num([1,3]))
3 2
Complexity¶
O(N^2) : N = len(nums)
O(1)
Approach 2 (Use Set)¶
Instead of linear search , lets build a set
def missing_num(nums):
n = len(nums)
nums_set = set(nums)
for i in range(1,n+2):
if i not in nums_set:
return i
print(missing_num([1,2,4,5]))
print(missing_num([1,3]))
3 2
Complexity¶
O(N) : N = len(nums)
O(N) : N = len(nums)
Approach 3 (Sorting)¶
- First Sort the array
- Find the missing number
def missing_num(nums):
n = len(nums)
sorted_nums = sorted(nums)
for i in range(n):
if sorted_nums[i] != i+1:
return i+1
print(missing_num([1,2,4,5]))
print(missing_num([1,3]))
3 2
Complexity¶
O(N log N) : N = len(nums)
O(N)
Approach 4 (Maths)¶
- sum of first n numbers = n * (n +1) /2 = S1
- sum of nums = S2
- result = S1 - S2
def missing_num(nums):
n = len(nums)
s1 = (n+1) * (n+2) / 2
s2 =0
for num in nums:
s2 += num
return int(s1 - s2)
print(missing_num([1,2,4,5]))
print(missing_num([1,3]))
3 2
Complexity¶
O(N)
O(1)
Count Maximum Consecutive One's in the array¶
Input: prices = {1, 1, 0, 1, 1, 1}
Output: 3
Input: prices = {1, 0, 1, 1, 0, 1}
Output: 2
Approach1¶
- Keep track of current count
- result = max(count)
def max_ones(nums):
result = 0
count =0
for num in nums:
if num ==1:
count +=1
result = max(result,count)
else:
count =0
return result
print(max_ones([1, 1, 0, 1, 1, 1]))
print(max_ones([1, 0, 1, 1, 0, 1]))
3 2
Complexity¶
O(N) : N = len(nums)
O(1)