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
slowpointer often keeps track of the current valid position, while thefastpointer 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 < nandodd < n:- If the element at the
evenindex is even (nums[even] % 2 == 0), moveevento the next even index (even += 2). - Else if the element at the
oddindex is odd (nums[odd] % 2 == 1), moveoddto the next odd index (odd += 2). - Else: Swap the elements at indices
evenandodd(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
numswhere 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 asnumsfilled 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
reswhere 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 of0and2respectively.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 move0to the left side. - Increment both
leftandi.
- Swap
- Else if
nums[i] == 2:- Swap
nums[i]withnums[right]to move2to the right side. - Decrement
right(do not incrementibecause swapped value needs to be checked).
- Swap
- Else (
nums[i] == 1):- Increment
ito process the next element.
- Increment
- If
- While
-
In-place result :
- At the end of the loop, the array
numswill be sorted with all0s first, followed by1s, then2s.
- At the end of the loop, the array
This is Dutch National Flag approach
-
Initialization :
low = 0: Pointer to the position where the next0should be placed.mid = 0: Pointer to the current element being examined.high = len(nums) - 1: Pointer to the position where the next2should be placed.
-
Loop through array :
- While
mid <= high:- If
nums[mid] == 0: Swapnums[low]andnums[mid], then increment bothlowandmid. - 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
numsis sorted in-place with all0s first, followed by1s, then2s.
- 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 innumsto strings for concatenation-based comparison.
-
Custom comparator :
compare(a, b):- Returns
-1ifa + bis greater thanb + a(meaningashould come beforeb). - Returns
1ifa + bis less thanb + a(meaningbshould come beforea). - Returns
0if 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
resultis'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 listnumsto 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 = 0andright = 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: Moveleftpointer right (left += 1) to increase the sum. - Else: Move
rightpointer 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
iand valuenum:- Calculate
complement = target - num. - If
complementexists 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]: Moveleftpointer right (left += 1) to try finding a taller line. - Else: Move
rightpointer 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
ifromlen(nums) - 1down to2:- Treat
nums[i]as the largest side of the triangle.
- Treat
- Loop
-
Two-pointer search for other sides :
- Set
left = 0andright = i - 1. - While
left < right:- If
nums[left] + nums[right] > nums[i]:- All pairs from
lefttoright-1withrightare valid (since the array is sorted). - Increment
countbyright - left. - Move
rightpointer left (right -= 1).
- All pairs from
- Else: Move
leftpointer 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
chins:- If
chis'I'(increase): Appendlowtoresand incrementlowby 1. - Else (
'D'for decrease): Appendhightoresand decrementhighby 1.
- If
- For each character
-
Append last element :
- Append
lowtores(at this point,low == high).
- Append
-
Return result :
- Return the permutation
resthat 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 from0tolen(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
jforward 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 = jto continue processing after the reversed section.
- Set
- Else (
'I'): Incrementiby 1 to move to the next character.
- If
- While
-
Return result :
- Return the modified list
arrwhich 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
powerbytokens[left], increasescoreby 1, moveleftpointer 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
powerbytokens[right], decreasescoreby 1, moverightpointer 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
tinremaining:- Create a new list
new_remainingexcluding 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 >= 0andnums[i] >= nums[i + 1]: Moveileftwards to find the first element that is smaller than its next element.
- While
-
Swap with next greater element :
- If
i >= 0:- Initialize
j = i + 1and 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
numswhich 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 >= 0andnums[i] >= nums[i + 1]: Moveileftwards until an element smaller than its next element is found.
- While
-
Swap with next greater element :
- If
i >= 0:- Set
j = n - 1and 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 + 1andright = n - 1. - While
left < right: Swapnums[left]andnums[right], then moveleftforward andrightbackward. - This ensures the suffix after position
iis in ascending order (smallest possible arrangement).
- Initialize
-
Result :
numsis 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
ifrom0tolen(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 + 1andright = 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
leftandrightpointers. - Move both pointers inward (
left += 1,right -= 1).
- Append the triplet
- Else if
curr_sum < 0: Moveleftpointer right to increase the sum. - Else: Move
rightpointer 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:
sentence2can be turned tosentence1by 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:
sentence2can be turned tosentence1by inserting "right now" at the end of the sentence.
Constraints:
1 <= sentence1.length, sentence2.length <= 100
sentence1andsentence2consist of lowercase and uppercase English letters and spaces.
The words insentence1andsentence2are 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
w1is the longer sentence :- If
len(w1) < len(w2), swapw1andw2.
- If
- Match from the start :
- Initialize
i = 0. - While
i < len(w2)andw1[i] == w2[i], incrementito count matching words from the beginning.
- Initialize
- Match from the end :
- Initialize
j = 0. - While
j < len(w2) - iandw1[-(j+1)] == w2[-(j+1)], incrementjto count matching words from the end.
- Initialize
- Check similarity condition :
- If
i + j == len(w2), returnTrue(all words inw2match 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
w1is the longer sentence :- If
len(w1) < len(w2), swapw1andw2.
- If
-
Store lengths :
n1 = len(w1),n2 = len(w2): Store lengths of both word lists for easy reference.
-
Check all prefix-suffix combinations :
- Loop
ifrom0ton2(possible prefix lengths). - For each
i, loopjfrom0ton2 - i(possible suffix lengths). - If
i + j <= n2and 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 indequefor 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
leftleftwards 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
leftleftwards 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
reswith 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
sconsists 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: Adjustskto handle cases wherekis greater thann.
-
Helper function
reverse(start, end):- Swaps elements from index
starttoendwhile moving pointers inward.
- Swaps elements from index
-
Rotation steps :
reverse(0, n - 1): Reverse the entire array.reverse(0, k - 1): Reverse the firstkelements.reverse(k, n - 1): Reverse the remainingn - kelements.
-
Result :
- The array
numsis rotated to the right byksteps in-place.
- The array
This is second approach
-
Initialization :
n = len(nums): Stores the total number of elements innums.k %= n: Adjustskto handle cases wherekis greater thann.arr = [0] * n: Creates a new array of sizeninitialized with zeros.
-
Positioning elements :
- For each index
iinnums:- Place
nums[i]into its new position(i + k) % ninarr.
- Place
- For each index
-
Copy back to original :
nums[:] = arr: Copies the rotated result fromarrback intonumsin-place.
-
Result :
- The array
numsis rotated to the right byksteps using extra space of sizen.
- The array