01. Two Pointer
Theory
Description
The Two Pointer Pattern is a technique used to solve problems involving sequences (such as arrays or lists) by utilizing two pointers that traverse the sequence in different ways. This approach is particularly effective in optimizing performance by reducing time complexity, especially for problems that involve checking pairs, subarrays, or sliding windows.
This technique should be your go-to when you see a question that involves searching for a pair (or more!) of elements in an array that meet a certain criteria.
Types
Same Direction
When to Use
- This technique is ideal for problems like finding unique elements, counting subarrays, or rearranging elements.
How It Works
- One pointer (typically called
slow
) moves through the array, while the other pointer (calledfast
) explores further elements. - The
slow
pointer often keeps track of the current valid position, while thefast
pointer scans for new valid elements. - This is especially useful for sliding window problems, where the window expands and shrinks by adjusting the pointers.
- It can also be used to remove duplicates in-place in an array.
1. Sort Array By Parity II (Leetcode:922)
Problem Statement
Given an array of integers nums, half of the integers in nums are odd, and the other half are even.
Sort the array so that whenever nums[i]
is odd, i
is odd, and whenever nums[i]
is even, i
is even.
Return any answer array that satisfies this condition.
Example 1:
Input: nums = [4,2,5,7]
Output: [4,5,2,7]
Explanation: [4,7,2,5], [2,5,4,7], [2,7,4,5] would also have been accepted.
Example 2:
Input: nums = [2,3]
Output: [2,3]
Constraints:
2 <= nums.length <= 2 * 10^4
nums.length is even.
Half of the integers in nums are even.
0 <= nums[i] <= 1000
Follow Up:
Could you solve it in-place?
Code and Explaination
-
Initialization :
even = 0, odd = 1
: Pointers to track the next even and odd indices respectively.n = len(nums)
: Stores the total number of elements innums
.
-
Loop through array :
- While
even < n
andodd < n
:- If the element at the
even
index is even (nums[even] % 2 == 0
), moveeven
to the next even index (even += 2
). - Else if the element at the
odd
index is odd (nums[odd] % 2 == 1
), moveodd
to the next odd index (odd += 2
). - Else: Swap the elements at indices
even
andodd
(nums[even], nums[odd] = nums[odd], nums[even]
), then move both pointers forward by 2.
- If the element at the
- While
-
Return result :
- After the loop, return the rearranged array
nums
where even indices hold even numbers and odd indices hold odd numbers.
- After the loop, return the rearranged array
-
Initialization :
evens = [x for x in nums if x % 2 == 0]
: Creates a list of all even numbers fromnums
.odds = [x for x in nums if x % 2 == 1]
: Creates a list of all odd numbers fromnums
.res = [0] * len(nums)
: Initializes a result list of the same length asnums
filled with zeros.
-
Fill positions :
res[0::2] = evens
: Assigns even numbers to even indices ofres
.res[1::2] = odds
: Assigns odd numbers to odd indices ofres
.
-
Return result :
- Return the list
res
where even indices contain even numbers and odd indices contain odd numbers.
- Return the list
Staged Traversal
When to Use
- Useful when the traversal involves conditional or nested passes, such as partitioning arrays, in-place rearrangements, or sorting by repeatedly scanning for conditions.
How It Works
- One pointer iterates through the data sequentially.
- When a certain condition is met, a second pointer or inner loop activates to perform an action (swap, scan, etc.).
- This staged, conditional movement allows fine-grained control of elements based on dynamic criteria.
1. Sort Colors (Leetcode:75)
Problem Statement
Given an array nums
with n
objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white, and blue.
We will use the integers 0
, 1
, and 2
to represent the color red, white, and blue, respectively.
You must solve this problem without using the library's sort function.
Example 1:
Input: nums = [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]
Example 2:
Input: nums = [2,0,1] Output: [0,1,2]
Constraints:
n == nums.length
1 <= n <= 300
nums[i] is either 0, 1, or 2.
Follow Up:
Could you come up with a one-pass algorithm using only constant extra space?
Code and Explaination
This is two pointer approach (partitioning array)
-
Initialization :
left = 0, right = len(nums) - 1
: Pointers for the next position of0
and2
respectively.i = 0
: Current index being processed.
-
Three-way partition (Dutch National Flag algorithm) :
- While
i <= right
:- If
nums[i] == 0
:- Swap
nums[i]
withnums[left]
to move0
to the left side. - Increment both
left
andi
.
- Swap
- Else if
nums[i] == 2
:- Swap
nums[i]
withnums[right]
to move2
to the right side. - Decrement
right
(do not incrementi
because swapped value needs to be checked).
- Swap
- Else (
nums[i] == 1
):- Increment
i
to process the next element.
- Increment
- If
- While
-
In-place result :
- At the end of the loop, the array
nums
will be sorted with all0
s first, followed by1
s, then2
s.
- At the end of the loop, the array
This is Dutch National Flag approach
-
Initialization :
low = 0
: Pointer to the position where the next0
should be placed.mid = 0
: Pointer to the current element being examined.high = len(nums) - 1
: Pointer to the position where the next2
should be placed.
-
Loop through array :
- While
mid <= high
:- If
nums[mid] == 0
: Swapnums[low]
andnums[mid]
, then increment bothlow
andmid
. - Else if
nums[mid] == 1
: Incrementmid
(correct position, move forward). - Else (
nums[mid] == 2
): Swapnums[mid]
andnums[high]
, then decrementhigh
.
- If
- While
-
Return result :
- The list
nums
is sorted in-place with all0
s first, followed by1
s, then2
s.
- The list
2. Largest Number (Leetcode:179)
Problem Statement
Given a list of non-negative integers nums
, arrange them such that they form the largest number and return it.
Since the result may be very large, so you need to return a string instead of an integer.
Example 1:
Input: nums = [10,2]
Output: "210"
Example 2:
Input: nums = [3,30,34,5,9]
Output: "9534330"
Constraints:
1 <= nums.length <= 100 0 <= nums[i] <= 109
Code and Explaination
This is optimal approach
-
Convert to strings :
nums_str = list(map(str, nums))
: Converts all integers innums
to strings for concatenation-based comparison.
-
Custom comparator :
compare(a, b)
:- Returns
-1
ifa + b
is greater thanb + a
(meaninga
should come beforeb
). - Returns
1
ifa + b
is less thanb + a
(meaningb
should come beforea
). - Returns
0
if they are equal.
- Returns
-
Sort using custom logic :
nums_str.sort(key=cmp_to_key(compare))
: Sorts the list of string numbers so that their concatenation forms the largest possible number.
-
Join to form result :
result = ''.join(nums_str)
: Combines all sorted string numbers into a single string.
-
Handle leading zeros :
- If the first character of
result
is'0'
, return'0'
(covers the case where all numbers are zeros). - Otherwise, return
result
.
- If the first character of
-
Result :
- Returns the largest number possible by arranging the integers in
nums
.
- Returns the largest number possible by arranging the integers in
This is bubble-sort approach
-
Initialization:
nums_str = list(map(str, nums))
: Converts all numbers in the input listnums
to strings to facilitate concatenation and comparison.n = len(nums_str)
: Stores the length of the input list.
-
Bubble Sort using Two Pointers:
- The algorithm uses nested loops (
for i in range(n)
andfor j in range(i + 1, n)
) to compare every possible pair of numbers. - For each pair
(i, j)
:- Custom Comparison:
Ifnums_str[i] + nums_str[j] < nums_str[j] + nums_str[i]
, their order is swapped. - This ensures that the concatenation of the numbers forms the largest possible number when joined.
- Example:
If comparing'3'
and'30'
: '3' + '30'
='330'
'30' + '3'
='303'
- Since
'330' > '303'
,'3'
should come before'30'
.
- Custom Comparison:
- The algorithm uses nested loops (
-
Result Construction:
''.join(nums_str)
: Concatenates the sorted strings into the final number.return '0' if result[0] == '0' else result
:- If the first digit is
'0'
, it means all numbers are zeros, so return'0'
. - Otherwise, return the concatenated result.
- If the first digit is
3. First Missing Positive (Leetcode:41)
Problem Statement
Given an unsorted integer array nums
. Return the smallest positive integer that is not present in nums
.
You must implement an algorithm that runs in O(n)
time and uses O(1)
auxiliary space.
Example 1:
Input: nums = [1,2,0]
Output: 3
Explanation: The numbers in the range [1,2] are all in the array.
Example 2:
Input: nums = [3,4,-1,1]
Output: 2
Explanation: 1 is in the array but 2 is missing.
Example 3:
Input: nums = [7,8,9,11,12]
Output: 1
Explanation: The smallest positive integer 1 is missing.
Constraints:
1 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
Code and Explaination
This is first approach
Opposite End
When to Use
- This technique is ideal for problems where you need to find pairs that satisfy a specific condition, such as a target sum or product, especially in sorted arrays.
How It Works
- One pointer starts at the beginning of the array (left pointer), and the other starts at the end (right pointer).
- Both pointers move towards each other, adjusting based on the condition being checked.
- If the sum of the values at both pointers meets the condition (e.g., equals a target sum), return the result.
- If the sum is too low, move the left pointer forward; if it's too high, move the right pointer backward.
- This method is efficient for problems like "two-sum" or "pair sum" problems in sorted arrays.
1. Two Sum (Leetcode:1)
Problem Statement
Given an array of integers nums
and an integer target
, return indices of the two numbers such that they add up to target
.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order.
Example 1:
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
Example 2:
Input: nums = [3,2,4], target = 6
Output: [1,2]
Example 3:
Input: nums = [3,3], target = 6
Output: [0,1]
Constraints:
2 <= nums.length <= 10^4
-10^9 <= nums[i] <= 10^9
-10^9 <= target <= 10^9
Only one valid answer exists.
Follow Up:
Can you come up with an algorithm that is less than
O(n^2)
time complexity?
Code and Explaination
This is using two pointers approach
-
Pair values with indices :
paired = [(num, i) for i, num in enumerate(nums)]
: Creates a list of tuples containing each number and its original index.
-
Sort pairs by value :
paired.sort(key=lambda x: x[0])
: Sorts the list of pairs based on the number (first element of each tuple).
-
Two-pointer search :
- Initialize
left = 0
andright = len(paired) - 1
. - While
left < right
:- Calculate
current_sum = paired[left][0] + paired[right][0]
. - If
current_sum == target
: Return the original indices[paired[left][1], paired[right][1]]
. - If
current_sum < target
: Moveleft
pointer right (left += 1
) to increase the sum. - Else: Move
right
pointer left (right -= 1
) to decrease the sum.
- Calculate
- Initialize
-
Error handling :
- If no pair is found (should not happen by constraints), raise a
ValueError
.
- If no pair is found (should not happen by constraints), raise a
This is optimal approach
-
Initialization :
num_map = {}
: A dictionary to store numbers as keys and their indices as values for quick lookups.
-
Loop through
nums
:- For each index
i
and valuenum
:- Calculate
complement = target - num
. - If
complement
exists innum_map
:- Return
[num_map[complement], i]
, which are the indices of the two numbers that sum to the target.
- Return
- Otherwise, store the current number and its index in
num_map
(num_map[num] = i
).
- Calculate
- For each index
-
Return result :
- The function returns as soon as a valid pair is found, ensuring O(n) time complexity.
2: Container With Most Water(Leetcode:11)
Problem Statement
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.
Notice that you may not slant the container.
Example 1:
Input: height = [1,8,6,2,5,4,8,3,7]
Output: 49
Explanation: The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.
Example 2:
Input: height = [1,1]
Output: 1
Constraints:
n == height.length
2 <= n <= 10^5
0 <= height[i] <= 10^4
Code and Explaination
This is both two pointer and greedy approach
-
Initialization :
left = 0, right = len(height) - 1
: Two pointers at the start and end of the list.max_area = 0
: Tracks the maximum container area found so far.
-
Two-pointer loop :
- While
left < right
:h = min(height[left], height[right])
: Height is determined by the shorter line.w = right - left
: Width is the distance between the two pointers.- Update
max_area = max(max_area, h * w)
to store the largest area found.
- While
-
Pointer movement :
- If
height[left] < height[right]
: Moveleft
pointer right (left += 1
) to try finding a taller line. - Else: Move
right
pointer left (right -= 1
) for the same reason.
- If
-
Return result :
- Return
max_area
, the largest possible water container area.
- Return
3: Valid Triangle Number(Leetcode:611)
Problem Statement
Given an integer array nums
, return the number of triplets chosen from the array that can make triangles if we take them as side lengths of a triangle.
Example 1:
Input: nums = [2,2,3,4]
Output: 3
Explanation: Valid combinations are:
2,3,4 (using the first 2)
2,3,4 (using the second 2)
2,2,3
Example 2:
Input: nums = [4,2,3,4]
Output: 4
Constraints:
1 <= nums.length <= 1000
0 <= nums[i] <= 1000
Code and Explaination
-
Sort the array :
nums.sort()
: Sorts the list in non-decreasing order to simplify the triangle inequality check.
-
Initialize counter :
count = 0
: Tracks the number of valid triangles.
-
Fix the largest side :
- Loop
i
fromlen(nums) - 1
down to2
:- Treat
nums[i]
as the largest side of the triangle.
- Treat
- Loop
-
Two-pointer search for other sides :
- Set
left = 0
andright = i - 1
. - While
left < right
:- If
nums[left] + nums[right] > nums[i]
:- All pairs from
left
toright-1
withright
are valid (since the array is sorted). - Increment
count
byright - left
. - Move
right
pointer left (right -= 1
).
- All pairs from
- Else: Move
left
pointer right (left += 1
) to increase the sum.
- If
- Set
-
Return result :
- Return
count
, the total number of valid triangles possible.
- Return
4. DI String Match (Leetcode:942)
Problem Statement
A permutation perm
of n + 1
integers of all the integers in the range [0, n]
can be represented as a string s
of length n
where:
s[i] == 'I' if perm[i] < perm[i + 1]
, and
s[i] == 'D' if perm[i] > perm[i + 1]
.
Given a string s
, reconstruct the permutation perm
and return it. If there are multiple valid permutations perm, return any of them.
Example 1:
Input: s = "IDID"
Output: [0,4,1,3,2]
Example 2:
Input: s = "III"
Output: [0,1,2,3]
Example 3:
Input: s = "DDI"
Output: [3,2,0,1]
Constraints:
1 <= s.length <= 10^5
s[i]
is either'I'
or'D'
.
Code and Explaination
This is Two Pointers (Greedy) approach
-
Initialization :
low = 0, high = len(s)
: Pointers to track the smallest and largest remaining numbers available.res = []
: Stores the permutation result.
-
Loop through string
s
:- For each character
ch
ins
:- If
ch
is'I'
(increase): Appendlow
tores
and incrementlow
by 1. - Else (
'D'
for decrease): Appendhigh
tores
and decrementhigh
by 1.
- If
- For each character
-
Append last element :
- Append
low
tores
(at this point,low == high
).
- Append
-
Return result :
- Return the permutation
res
that satisfies the'I'
and'D'
constraints.
- Return the permutation
This is Stack Reversal approach
-
Initialization :
arr = list(range(len(s) + 1))
: Creates a list of numbers from0
tolen(s)
in ascending order.i = 0
: Pointer to iterate through the strings
.
-
Loop through string
s
:- While
i < len(s)
:- If
s[i] == 'D'
:- Set
j = i
. - Move
j
forward whiles[j]
is'D'
to find the end of the consecutive'D'
sequence. - Reverse the subarray
arr[i:j+1]
to satisfy the descending order requirement. - Set
i = j
to continue processing after the reversed section.
- Set
- Else (
'I'
): Incrementi
by 1 to move to the next character.
- If
- While
-
Return result :
- Return the modified list
arr
which satisfies the'I'
and'D'
pattern ins
.
- Return the modified list
5. Bag of Tokens (Leetcode:948)
Problem Statement
You start with an initial power of power
, an initial score of 0
, and a bag of tokens given as an integer array tokens
, where each tokens[i]
denotes the value of tokeni
.
Your goal is to maximize the total score by strategically playing these tokens. In one move, you can play an unplayed token in one of the two ways (but not both for the same token):
Face-up: If your current power is at least tokens[i]
, you may play tokeni, losing tokens[i]
power and gaining 1
score.
Face-down: If your current score is at least 1
, you may play tokeni, gaining tokens[i]
power and losing 1
score.
Return the maximum possible score you can achieve after playing any number of tokens.
Example 1:
Input: tokens = [100], power = 50
Output: 0
Explanation: Since your score is 0 initially, you cannot play the token face-down. You also cannot play it face-up since your power (50) is less than tokens[0] (100).
Example 2:
Input: tokens = [200,100], power = 150
Output: 1
Explanation: Play token1 (100) face-up, reducing your power to 50 and increasing your score to 1.
There is no need to play token0, since you cannot play it face-up to add to your score. The maximum score achievable is 1.
Example 3:
Input: tokens = [100,200,300,400], power = 200
Output: 2
Explanation: Play the tokens in this order to get a score of 2:
Play token0 (100) face-up, reducing power to 100 and increasing score to 1.
Play token3 (400) face-down, increasing power to 500 and reducing score to 0.
Play token1 (200) face-up, reducing power to 300 and increasing score to 1.
Play token2 (300) face-up, reducing power to 0 and increasing score to 2.
The maximum score achievable is 2.
Constraints:
0 <= tokens.length <= 1000
0 <= tokens[i], power < 104
Code and Explaination
This is two pointer (greedy) approach
-
Sort tokens :
tokens.sort()
: Sorts tokens in ascending order to use the smallest token for gaining score and the largest for regaining power.
-
Initialization :
left, right = 0, len(tokens) - 1
: Two pointers for the smallest and largest remaining tokens.score = 0
: Current score.max_score = 0
: Maximum score achieved so far.
-
Process tokens :
- While
left <= right
:- If
power >= tokens[left]
:- Play the smallest token face up: reduce
power
bytokens[left]
, increasescore
by 1, moveleft
pointer right. - Update
max_score = max(max_score, score)
.
- Play the smallest token face up: reduce
- Else if
score > 0
:- Play the largest token face down: increase
power
bytokens[right]
, decreasescore
by 1, moveright
pointer left.
- Play the largest token face down: increase
- Else:
- Break the loop if neither action is possible.
- If
- While
-
Return result :
- Return
max_score
, the highest score obtained during the process.
- Return
This is Brute-force approach
-
Initialization :
max_score = 0
: Tracks the highest score obtained during the search.
-
Depth-first search (DFS) function :
dfs(remaining, p, s)
:remaining
: List of tokens not yet played.p
: Current available power.s
: Current score.- Update
max_score = max(max_score, s)
to record the best score so far.
-
Explore choices for each token :
- Loop through each token
t
inremaining
:- Create a new list
new_remaining
excluding the chosen token. - If
p >= t
(enough power), simulate playing the token face-up:- Call
dfs(new_remaining, p - t, s + 1)
.
- Call
- If
s >= 1
(enough score), simulate playing the token face-down:- Call
dfs(new_remaining, p + t, s - 1)
.
- Call
- Create a new list
- Loop through each token
-
Return result :
- Start DFS with
dfs(tokens, power, 0)
. - Return
max_score
, the maximum achievable score after exploring all play orders.
- Start DFS with
6. Next Permutation (Leetcode:31)
Problem Statement
A permutation of an array of integers is an arrangement of its members into a sequence or linear order.
- For example, for
arr = [1,2,3]
, the following are all the permutations ofarr: [1,2,3], [1,3,2], [2, 1, 3], [2, 3, 1], [3,1,2], [3,2,1]
.
The next permutation of an array of integers is the next lexicographically greater permutation of its integer. More formally, if all the permutations of the array are sorted in one container according to their lexicographical order, then the next permutation of that array is the permutation that follows it in the sorted container. If such arrangement is not possible, the array must be rearranged as the lowest possible order (i.e., sorted in ascending order).
- For example, the next permutation of
arr = [1,2,3]
is[1,3,2]
. - Similarly, the next permutation of
arr = [2,3,1]
is[3,1,2]
. - While the next permutation of
arr = [3,2,1]
is[1,2,3]
because[3,2,1]
does not have a lexicographical larger rearrangement.
Given an array of integers nums
, find the next permutation of nums
.
The replacement must be in place and use only constant extra memory.
Example 1:
Input: nums = [1,2,3]
Output: [1,3,2]
Example 2:
Input: nums = [3,2,1]
Output: [1,2,3]
Example 3:
Input: nums = [1,1,5]
Output: [1,5,1]
Constraints:
1 <= nums.length <= 100
0 <= nums[i] <= 100
Code and Explaination
This is sort from pivot approach
-
Initialization :
n = len(nums)
: Stores the total number of elements innums
.i = n - 2
: Starts from the second last index to find the first decreasing element from the right.
-
Find pivot :
- While
i >= 0
andnums[i] >= nums[i + 1]
: Movei
leftwards to find the first element that is smaller than its next element.
- While
-
Swap with next greater element :
- If
i >= 0
:- Initialize
j = i + 1
and move it rightwards whilenums[j] > nums[i]
. - Swap
nums[i]
withnums[j - 1]
(the smallest element greater thannums[i]
to the right).
- Initialize
- If
-
Rearrange suffix :
- Sort the subarray
nums[i+1:]
to get the smallest lexicographic order for the suffix.
- Sort the subarray
-
Return result :
- Return the modified
nums
which now represents the next lexicographical permutation.
- Return the modified
This is optimal in-place (two pointer) approach
-
Initialization :
n = len(nums)
: Stores the total number of elements innums
.i = n - 2
: Starts from the second last index to find the first decreasing element from the right.
-
Find pivot :
- While
i >= 0
andnums[i] >= nums[i + 1]
: Movei
leftwards until an element smaller than its next element is found.
- While
-
Swap with next greater element :
- If
i >= 0
:- Set
j = n - 1
and move it leftwards untilnums[j] > nums[i]
. - Swap
nums[i]
andnums[j]
(placing the next larger number in the pivot position).
- Set
- If
-
Reverse suffix :
- Initialize
left = i + 1
andright = n - 1
. - While
left < right
: Swapnums[left]
andnums[right]
, then moveleft
forward andright
backward. - This ensures the suffix after position
i
is in ascending order (smallest possible arrangement).
- Initialize
-
Result :
nums
is now rearranged to the next lexicographical permutation in-place.
7. 3Sum (Leetcode:15)
Problem Statement
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
.
Notice that the solution set must not contain duplicate triplets.
Example 1:
Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Explanation:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
The distinct triplets are [-1,0,1] and [-1,-1,2].
Notice that the order of the output and the order of the triplets does not matter.
Example 2:
Input: nums = [0,1,1]
Output: []
Explanation: The only possible triplet does not sum up to 0.
Example 3:
Input: nums = [0,0,0]
Output: [[0,0,0]]
Explanation: The only possible triplet sums up to 0.
Constraints:
3 <= nums.length <= 3000
-10^5 <= nums[i] <= 10^5
Code and Explaination
This is first approach
-
Sort the array :
nums.sort()
: Sorts the list in ascending order to enable the two-pointer approach and easy duplicate handling.
-
Initialize result list :
res = []
: Stores unique triplets that sum to zero.
-
Loop to fix the first element :
- For
i
from0
tolen(nums) - 3
:- Skip duplicates for the first element by checking
if i > 0 and nums[i] == nums[i - 1]
.
- Skip duplicates for the first element by checking
- For
-
Two-pointer search for the other two elements :
- Set
left = i + 1
andright = len(nums) - 1
. - While
left < right
:- Compute
curr_sum = nums[i] + nums[left] + nums[right]
. - If
curr_sum == 0
:- Append the triplet
[nums[i], nums[left], nums[right]]
tores
. - Skip duplicates for
left
andright
pointers. - Move both pointers inward (
left += 1
,right -= 1
).
- Append the triplet
- Else if
curr_sum < 0
: Moveleft
pointer right to increase the sum. - Else: Move
right
pointer left to decrease the sum.
- Compute
- Set
-
Return result :
- Return
res
, the list of all unique triplets with sum equal to zero.
- Return
8: Three Sum Closest(Leetcode:16)
Problem Statement
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.
Example 1:
Input: nums = [-1,2,1,-4], target = 1
Output: 2
Explanation: The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
Example 2:
Input: nums = [0,0,0], target = 1
Output: 0
Explanation: The sum that is closest to the target is 0. (0 + 0 + 0 = 0).
Constraints:
3 <= nums.length <= 500
-1000 <= nums[i] <= 1000
-10^4 <= target <= 10^4
Code and Explaination
This is first approach
This is second approach
9. Sentence Similarity III (Leetcode:1813)
Problem Statement
You are given two strings sentence1
and sentence2
, each representing a sentence composed of words. A sentence is a list of words that are separated by a single space with no leading or trailing spaces. Each word consists of only uppercase and lowercase English characters.
Two sentences s1
and s2
are considered similar if it is possible to insert an arbitrary sentence (possibly empty) inside one of these sentences such that the two sentences become equal. Note that the inserted sentence must be separated from existing words by spaces.
For example,
-
s1 = "Hello Jane"
ands2 = "Hello my name is Jane"
can be made equal by inserting"my name is"
between"Hello"
and"Jane"
in s1. -
s1 = "Frog cool"
ands2 = "Frogs are cool"
are not similar, since although there is a sentence"s are"
inserted intos1
, it is not separated from"Frog"
by a space.
Given two sentences sentence1
and sentence2
, return true if sentence1
and sentence2
are similar. Otherwise, return false.
Example 1:
Input: sentence1 = "My name is Haley", sentence2 = "My Haley"
Output: true
Explanation:
sentence2
can be turned tosentence1
by inserting "name is" between "My" and "Haley".
Example 2:
Input: sentence1 = "of", sentence2 = "A lot of words"
Output: false
Explanation:
No single sentence can be inserted inside one of the sentences to make it equal to the other.
Example 3:
Input: sentence1 = "Eating right now", sentence2 = "Eating"
Output: true
Explanation:
sentence2
can be turned tosentence1
by inserting "right now" at the end of the sentence.
Constraints:
1 <= sentence1.length, sentence2.length <= 100
sentence1
andsentence2
consist of lowercase and uppercase English letters and spaces.
The words insentence1
andsentence2
are separated by a single space.
Code and Explaination
This is optimal(two pointer) approach
- Split sentences into words :
w1 = sentence1.split()
,w2 = sentence2.split()
: Convert both sentences into lists of words.
- Ensure
w1
is the longer sentence :- If
len(w1) < len(w2)
, swapw1
andw2
.
- If
- Match from the start :
- Initialize
i = 0
. - While
i < len(w2)
andw1[i] == w2[i]
, incrementi
to count matching words from the beginning.
- Initialize
- Match from the end :
- Initialize
j = 0
. - While
j < len(w2) - i
andw1[-(j+1)] == w2[-(j+1)]
, incrementj
to count matching words from the end.
- Initialize
- Check similarity condition :
- If
i + j == len(w2)
, returnTrue
(all words inw2
match either at the start or end ofw1
). - Otherwise, return
False
.
- If
This is Brute-force approach
-
Split sentences into words :
w1 = sentence1.split()
,w2 = sentence2.split()
: Convert both sentences into lists of words.
-
Ensure
w1
is the longer sentence :- If
len(w1) < len(w2)
, swapw1
andw2
.
- If
-
Store lengths :
n1 = len(w1)
,n2 = len(w2)
: Store lengths of both word lists for easy reference.
-
Check all prefix-suffix combinations :
- Loop
i
from0
ton2
(possible prefix lengths). - For each
i
, loopj
from0
ton2 - i
(possible suffix lengths). - If
i + j <= n2
and both conditions hold:w1[:i] == w2[:i]
(prefix match)w1[-j:] == w2[-j:]
(suffix match)
→ ReturnTrue
.
- Loop
-
Return result :
- If no valid prefix-suffix combination is found, return
False
.
- If no valid prefix-suffix combination is found, return
This is deque approach
-
Convert sentences to deques :
dq1 = deque(sentence1.split())
,dq2 = deque(sentence2.split())
: Split each sentence into words and store them indeque
for efficient pops from both ends.
-
Match words from the start :
- While both deques are non-empty and their first words match (
dq1[0] == dq2[0]
):- Remove the first word from both (
popleft()
).
- Remove the first word from both (
- While both deques are non-empty and their first words match (
-
Match words from the end :
- While both deques are non-empty and their last words match (
dq1[-1] == dq2[-1]
):- Remove the last word from both (
pop()
).
- Remove the last word from both (
- While both deques are non-empty and their last words match (
-
Return similarity result :
- If either deque is empty (
not dq1 or not dq2
), returnTrue
(all words in the shorter sentence match either at the start or end of the longer one). - Otherwise, return
False
.
- If either deque is empty (
10. Reverse Words in a String (Leetcode:151)
Problem Statement
Given an input string s
, reverse the order of the words.
A word is defined as a sequence of non-space characters. The words in s
will be separated by at least one space.
Return a string of the words in reverse order concatenated by a single space.
Note that s
may contain leading or trailing spaces or multiple spaces between two words. The returned string should only have a single space separating the words. Do not include any extra spaces.
Example 1:
Input: s = "the sky is blue"
Output: "blue is sky the"
Example 2:
Input: s = " hello world "
Output: "world hello"
Explanation: Your reversed string should not contain leading or trailing spaces.
Example 3:
Input: s = "a good example"
Output: "example good a"
Explanation: You need to reduce multiple spaces between two words to a single space in the reversed string.
Constraints:
1 <= s.length <= 104
s contains English letters (upper-case and lower-case), digits, and spaces ' '.
There is at least one word in s.
Code and Explaination
This is first approach
-
Initialization :
res = []
: List to store extracted words in reverse order.left = right = len(s) - 1
: Pointers starting at the last character of the string.
-
Process words from end to start :
- While
left >= 0
:- Skip trailing spaces by moving
left
leftwards whiles[left] == " "
. - If
left < 0
, break the loop (no more words).
- Skip trailing spaces by moving
- While
-
Identify a word :
- Set
right = left
(marks the end of the current word). - Move
left
leftwards until a space is found or the start of the string is reached (s[left] != " "
).
- Set
-
Store the word :
- Append the substring
s[left+1:right+1]
(the current word) tores
.
- Append the substring
-
Return result :
- Join the words in
res
with a single space (" ".join(res)
) and return the reversed sentence without extra spaces.
- Join the words in
Sliding Window
When to Use
- Ideal for problems involving contiguous subarrays or substrings, such as finding maximum sums, longest substring without repeats, or counting subarrays with certain properties.
How It Works
- Two pointers define a dynamic window: start and end.
- The window expands or shrinks by moving pointers based on conditions (e.g., sum, uniqueness).
- Efficiently processes elements in a linear pass without redundant checks.
1. Contains Duplicate III (Leetcode:220)
Problem Statement
You are given an integer array nums
and two integers indexDiff
and valueDiff
.
Find a pair of indices (i, j)
such that:
i != j
,
abs(i - j) <= indexDiff
.
abs(nums[i] - nums[j]) <= valueDiff
, and
Return true
if such pair exists or false
otherwise.
Example 1:
Input: nums = [1,2,3,1], indexDiff = 3, valueDiff = 0
Output: true
Explanation: We can choose (i, j) = (0, 3).
We satisfy the three conditions:
i != j --> 0 != 3
abs(i - j) <= indexDiff --> abs(0 - 3) <= 3
abs(nums[i] - nums[j]) <= valueDiff --> abs(1 - 1) <= 0
Example 2:
Input: nums = [1,5,9,1,5,9], indexDiff = 2, valueDiff = 3
Output: false
Explanation: After trying all the possible pairs (i, j), we cannot satisfy the three conditions, so we return false.
Constraints:
2 <= nums.length <= 10^5
-10^9 <= nums[i] <= 10^9
1 <= indexDiff <= nums.length
0 <= valueDiff <= 10^9
Code and Explaination
This is sliding window + BST approach
This is Bucket sort Hashing approach
2. Longest Repeating Character Replacement (Leetcode:424)
Problem Statement
You are given a string s
and an integer k
. You can choose any character of the string and change it to any other uppercase English character. You can perform this operation at most k
times.
Return the length of the longest substring containing the same letter you can get after performing the above operations.
Example 1:
Input: s = "ABAB", k = 2
Output: 4
Explanation: Replace the two 'A's with two 'B's or vice versa.
Example 2:
Input: s = "AABABBA", k = 1
Output: 4
Explanation: Replace the one 'A' in the middle with 'B' and form "AABBBBA".
The substring "BBBB" has the longest repeating letters, which is 4.
There may exists other ways to achieve this answer too.
Constraints:
1 <= s.length <= 10^5
s
consists of only uppercase English letters.
0 <= k <= s.length
Code and Explaination
This is optimal sliding window approach
This is sliding window + dictionary approach
Divide and Conquer
1. Rotate Array (Leetcode:189)
Problem Statement
Given an integer array nums
, rotate the array to the right by k
steps, where k
is non-negative.
Example 1:
Input: nums = [-1,-100,3,99], k = 2
Output: [3,99,-1,-100]
Explanation:
rotate 1 steps to the right: [99,-1,-100,3]
rotate 2 steps to the right: [3,99,-1,-100]
Example 2:
Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]
Constraints:
1 <= nums.length <= 10^5
-2^31 <= nums[i] <= 2^31 ^- 1
0 <= k <= 10^5
Code and Explaination
This is optimal approach
-
Initialization :
n = len(nums)
: Stores the total number of elements innums
.k %= n
: Adjustsk
to handle cases wherek
is greater thann
.
-
Helper function
reverse(start, end)
:- Swaps elements from index
start
toend
while moving pointers inward.
- Swaps elements from index
-
Rotation steps :
reverse(0, n - 1)
: Reverse the entire array.reverse(0, k - 1)
: Reverse the firstk
elements.reverse(k, n - 1)
: Reverse the remainingn - k
elements.
-
Result :
- The array
nums
is rotated to the right byk
steps in-place.
- The array
This is second approach
-
Initialization :
n = len(nums)
: Stores the total number of elements innums
.k %= n
: Adjustsk
to handle cases wherek
is greater thann
.arr = [0] * n
: Creates a new array of sizen
initialized with zeros.
-
Positioning elements :
- For each index
i
innums
:- Place
nums[i]
into its new position(i + k) % n
inarr
.
- Place
- For each index
-
Copy back to original :
nums[:] = arr
: Copies the rotated result fromarr
back intonums
in-place.
-
Result :
- The array
nums
is rotated to the right byk
steps using extra space of sizen
.
- The array