Linear Time O(n) — Optimize¶
Table of Contents¶
- Exercise 1: Contains Duplicate — O(n^2) to O(n)
- Exercise 2: Two Sum — O(n^2) to O(n)
- Exercise 3: Maximum Subarray Sum — O(n^3) to O(n)
- Exercise 4: Find Missing Number — O(n log n) to O(n)
- Exercise 5: Intersection of Two Arrays — O(n*m) to O(n+m)
- Exercise 6: String Compression — O(n^2) to O(n)
- Exercise 7: First Duplicate — O(n^2) to O(n)
- Exercise 8: Maximum Sliding Window Sum — O(n*k) to O(n)
- Exercise 9: Sort Array of 0s, 1s, 2s — O(n log n) to O(n)
- Exercise 10: Product Except Self — O(n^2) to O(n)
- Exercise 11: Majority Element — O(n log n) to O(n)
- Exercise 12: Longest Consecutive Sequence — O(n log n) to O(n)
Exercise 1: Contains Duplicate — O(n^2) to O(n)¶
Slow Version — O(n^2)¶
Go:
func containsDuplicate(nums []int) bool {
for i := 0; i < len(nums); i++ {
for j := i + 1; j < len(nums); j++ {
if nums[i] == nums[j] {
return true
}
}
}
return false
}
Java:
public static boolean containsDuplicate(int[] nums) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] == nums[j]) return true;
}
}
return false;
}
Python:
def contains_duplicate(nums: list[int]) -> bool:
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] == nums[j]:
return True
return False
Your Task¶
Optimize to O(n) using a hash set.
Optimized Solution — O(n)
**Go:**func containsDuplicate(nums []int) bool {
seen := make(map[int]bool)
for _, v := range nums {
if seen[v] {
return true
}
seen[v] = true
}
return false
}
Exercise 2: Two Sum — O(n^2) to O(n)¶
Slow Version — O(n^2)¶
Go:
func twoSum(nums []int, target int) (int, int) {
for i := 0; i < len(nums); i++ {
for j := i + 1; j < len(nums); j++ {
if nums[i]+nums[j] == target {
return i, j
}
}
}
return -1, -1
}
Java:
public static int[] twoSum(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) {
return new int[]{i, j};
}
}
}
return new int[]{-1, -1};
}
Python:
def two_sum(nums: list[int], target: int) -> tuple[int, int]:
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
return (i, j)
return (-1, -1)
Your Task¶
Optimize to O(n) using a hash map to store complements.
Optimized Solution — O(n)
**Go:**func twoSum(nums []int, target int) (int, int) {
seen := make(map[int]int) // value -> index
for i, v := range nums {
if j, ok := seen[target-v]; ok {
return j, i
}
seen[v] = i
}
return -1, -1
}
public static int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> seen = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (seen.containsKey(complement)) {
return new int[]{seen.get(complement), i};
}
seen.put(nums[i], i);
}
return new int[]{-1, -1};
}
Exercise 3: Maximum Subarray Sum — O(n^3) to O(n)¶
Slow Version — O(n^3)¶
Go:
func maxSubArray(nums []int) int {
n := len(nums)
maxSum := nums[0]
for i := 0; i < n; i++ {
for j := i; j < n; j++ {
sum := 0
for k := i; k <= j; k++ {
sum += nums[k]
}
if sum > maxSum {
maxSum = sum
}
}
}
return maxSum
}
Java:
public static int maxSubArray(int[] nums) {
int maxSum = nums[0];
for (int i = 0; i < nums.length; i++) {
for (int j = i; j < nums.length; j++) {
int sum = 0;
for (int k = i; k <= j; k++) {
sum += nums[k];
}
maxSum = Math.max(maxSum, sum);
}
}
return maxSum;
}
Python:
def max_sub_array(nums: list[int]) -> int:
max_sum = nums[0]
n = len(nums)
for i in range(n):
for j in range(i, n):
current = sum(nums[i:j+1])
max_sum = max(max_sum, current)
return max_sum
Your Task¶
Optimize to O(n) using Kadane's algorithm.
Optimized Solution — O(n)
**Go:**func maxSubArray(nums []int) int {
currentMax := nums[0]
globalMax := nums[0]
for i := 1; i < len(nums); i++ {
if currentMax+nums[i] > nums[i] {
currentMax += nums[i]
} else {
currentMax = nums[i]
}
if currentMax > globalMax {
globalMax = currentMax
}
}
return globalMax
}
Exercise 4: Find Missing Number — O(n log n) to O(n)¶
Slow Version — O(n log n)¶
Given an array containing n distinct numbers from 0 to n, find the missing number.
Go:
import "sort"
func missingNumber(nums []int) int {
sort.Ints(nums)
for i, v := range nums {
if v != i {
return i
}
}
return len(nums)
}
Java:
public static int missingNumber(int[] nums) {
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
if (nums[i] != i) return i;
}
return nums.length;
}
Python:
def missing_number(nums: list[int]) -> int:
nums.sort()
for i, v in enumerate(nums):
if v != i:
return i
return len(nums)
Your Task¶
Optimize to O(n) using the sum formula or XOR.
Optimized Solution — O(n) with Sum
**Go:**func missingNumber(nums []int) int {
n := len(nums)
expectedSum := n * (n + 1) / 2
actualSum := 0
for _, v := range nums {
actualSum += v
}
return expectedSum - actualSum
}
Exercise 5: Intersection of Two Arrays — O(n*m) to O(n+m)¶
Slow Version — O(n*m)¶
Go:
func intersection(nums1, nums2 []int) []int {
var result []int
for _, a := range nums1 {
for _, b := range nums2 {
if a == b {
// Check if already in result
found := false
for _, r := range result {
if r == a {
found = true
break
}
}
if !found {
result = append(result, a)
}
break
}
}
}
return result
}
Python:
def intersection(nums1: list[int], nums2: list[int]) -> list[int]:
result = []
for a in nums1:
for b in nums2:
if a == b and a not in result:
result.append(a)
break
return result
Your Task¶
Optimize to O(n + m) using sets.
Optimized Solution — O(n + m)
**Go:**func intersection(nums1, nums2 []int) []int {
set1 := make(map[int]bool)
for _, v := range nums1 {
set1[v] = true
}
seen := make(map[int]bool)
var result []int
for _, v := range nums2 {
if set1[v] && !seen[v] {
result = append(result, v)
seen[v] = true
}
}
return result
}
Exercise 6: String Compression — O(n^2) to O(n)¶
Slow Version — O(n^2) due to string concatenation¶
Python:
def compress(s: str) -> str:
result = ""
i = 0
while i < len(s):
count = 1
while i + count < len(s) and s[i + count] == s[i]:
count += 1
result += s[i] + str(count) # O(n) string copy each time!
i += count
return result
Java:
public static String compress(String s) {
String result = "";
int i = 0;
while (i < s.length()) {
int count = 1;
while (i + count < s.length() && s.charAt(i + count) == s.charAt(i)) {
count++;
}
result += s.charAt(i) + "" + count; // O(n) string copy each time!
i += count;
}
return result;
}
Your Task¶
Optimize to O(n) using StringBuilder / list.
Optimized Solution — O(n)
**Go:**import (
"fmt"
"strings"
)
func compress(s string) string {
var sb strings.Builder
i := 0
for i < len(s) {
count := 1
for i+count < len(s) && s[i+count] == s[i] {
count++
}
sb.WriteByte(s[i])
fmt.Fprintf(&sb, "%d", count)
i += count
}
return sb.String()
}
Exercise 7: First Duplicate — O(n^2) to O(n)¶
Slow Version — O(n^2)¶
Go:
func firstDuplicate(arr []int) int {
for i := 0; i < len(arr); i++ {
for j := 0; j < i; j++ {
if arr[i] == arr[j] {
return arr[i]
}
}
}
return -1
}
Python:
def first_duplicate(arr: list[int]) -> int:
for i in range(len(arr)):
for j in range(i):
if arr[i] == arr[j]:
return arr[i]
return -1
Your Task¶
Optimize to O(n) using a hash set.
Optimized Solution — O(n)
**Go:**func firstDuplicate(arr []int) int {
seen := make(map[int]bool)
for _, v := range arr {
if seen[v] {
return v
}
seen[v] = true
}
return -1
}
Exercise 8: Maximum Sliding Window Sum — O(n*k) to O(n)¶
Slow Version — O(n*k)¶
Go:
func maxSumWindow(arr []int, k int) int {
maxSum := 0
for i := 0; i <= len(arr)-k; i++ {
sum := 0
for j := i; j < i+k; j++ {
sum += arr[j]
}
if i == 0 || sum > maxSum {
maxSum = sum
}
}
return maxSum
}
Python:
def max_sum_window(arr: list[int], k: int) -> int:
max_sum = float("-inf")
for i in range(len(arr) - k + 1):
current = sum(arr[i:i+k])
max_sum = max(max_sum, current)
return max_sum
Your Task¶
Optimize to O(n) using the sliding window technique.
Optimized Solution — O(n)
**Go:**func maxSumWindow(arr []int, k int) int {
windowSum := 0
for i := 0; i < k; i++ {
windowSum += arr[i]
}
maxSum := windowSum
for i := k; i < len(arr); i++ {
windowSum += arr[i] - arr[i-k]
if windowSum > maxSum {
maxSum = windowSum
}
}
return maxSum
}
Exercise 9: Sort Array of 0s, 1s, 2s — O(n log n) to O(n)¶
Slow Version — O(n log n)¶
Python:
Your Task¶
Optimize to O(n) using the Dutch National Flag algorithm (three pointers).
Optimized Solution — O(n)
**Go:**func sortColors(nums []int) {
low, mid, high := 0, 0, len(nums)-1
for mid <= high {
switch nums[mid] {
case 0:
nums[low], nums[mid] = nums[mid], nums[low]
low++
mid++
case 1:
mid++
case 2:
nums[mid], nums[high] = nums[high], nums[mid]
high--
}
}
}
public static void sortColors(int[] nums) {
int low = 0, mid = 0, high = nums.length - 1;
while (mid <= high) {
if (nums[mid] == 0) {
int tmp = nums[low]; nums[low] = nums[mid]; nums[mid] = tmp;
low++; mid++;
} else if (nums[mid] == 1) {
mid++;
} else {
int tmp = nums[mid]; nums[mid] = nums[high]; nums[high] = tmp;
high--;
}
}
}
Exercise 10: Product Except Self — O(n^2) to O(n)¶
Slow Version — O(n^2)¶
Go:
func productExceptSelf(nums []int) []int {
n := len(nums)
result := make([]int, n)
for i := 0; i < n; i++ {
product := 1
for j := 0; j < n; j++ {
if j != i {
product *= nums[j]
}
}
result[i] = product
}
return result
}
Python:
def product_except_self(nums: list[int]) -> list[int]:
n = len(nums)
result = [1] * n
for i in range(n):
for j in range(n):
if j != i:
result[i] *= nums[j]
return result
Your Task¶
Optimize to O(n) using prefix and suffix products.
Optimized Solution — O(n)
**Go:**func productExceptSelf(nums []int) []int {
n := len(nums)
result := make([]int, n)
// Left pass: result[i] = product of all elements to the left of i
result[0] = 1
for i := 1; i < n; i++ {
result[i] = result[i-1] * nums[i-1]
}
// Right pass: multiply by product of all elements to the right
rightProduct := 1
for i := n - 1; i >= 0; i-- {
result[i] *= rightProduct
rightProduct *= nums[i]
}
return result
}
public static int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] result = new int[n];
result[0] = 1;
for (int i = 1; i < n; i++) {
result[i] = result[i - 1] * nums[i - 1];
}
int rightProduct = 1;
for (int i = n - 1; i >= 0; i--) {
result[i] *= rightProduct;
rightProduct *= nums[i];
}
return result;
}
Exercise 11: Majority Element — O(n log n) to O(n)¶
Slow Version — O(n log n)¶
Python:
Your Task¶
Optimize to O(n) using Boyer-Moore Voting Algorithm.
Optimized Solution — O(n) time, O(1) space
**Go:**func majorityElement(nums []int) int {
candidate := nums[0]
count := 1
for i := 1; i < len(nums); i++ {
if count == 0 {
candidate = nums[i]
count = 1
} else if nums[i] == candidate {
count++
} else {
count--
}
}
return candidate
}
Exercise 12: Longest Consecutive Sequence — O(n log n) to O(n)¶
Slow Version — O(n log n)¶
Python:
def longest_consecutive(nums: list[int]) -> int:
if not nums:
return 0
nums.sort()
longest = 1
current = 1
for i in range(1, len(nums)):
if nums[i] == nums[i-1]:
continue
if nums[i] == nums[i-1] + 1:
current += 1
longest = max(longest, current)
else:
current = 1
return longest
Your Task¶
Optimize to O(n) using a hash set.
Optimized Solution — O(n)
**Go:**func longestConsecutive(nums []int) int {
numSet := make(map[int]bool)
for _, v := range nums {
numSet[v] = true
}
longest := 0
for num := range numSet {
// Only start counting from the beginning of a sequence
if !numSet[num-1] {
current := num
length := 1
for numSet[current+1] {
current++
length++
}
if length > longest {
longest = length
}
}
}
return longest
}
public static int longestConsecutive(int[] nums) {
Set<Integer> numSet = new HashSet<>();
for (int v : nums) numSet.add(v);
int longest = 0;
for (int num : numSet) {
if (!numSet.contains(num - 1)) { // start of sequence
int current = num;
int length = 1;
while (numSet.contains(current + 1)) {
current++;
length++;
}
longest = Math.max(longest, length);
}
}
return longest;
}