mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 13:12:44 +00:00
feat: refactored docs structure
This commit is contained in:
1 parent
d388b3000e
commit
9de25fecff
212 files changed
+641
-4169
No files matched your search
-74
@@ -1,74 +0,0 @@
|
||||
---
|
||||
title: '153. Find Minimum in Rotated Sorted Array'
|
||||
description: 'Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become:'
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
video: "nIVW4P8b1VA"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/62"
|
||||
sidebar:
|
||||
label: 'Find Minimum in Rotated Sorted Array'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]].
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [3,4,5,1,2]`
|
||||
- Output: `1`
|
||||
- Explanation: The original array was `[1,2,3,4,5]` rotated `3` times.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [4,5,6,7,0,1,2]`
|
||||
- Output: `0`
|
||||
- Explanation: The original array was `[0,1,2,4,5,6,7]` and it was rotated `4` times.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [11,13,15,17]`
|
||||
- Output: `11`
|
||||
- Explanation: The original array was `[11,13,15,17]` and it was rotated `4` times.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == nums.length`
|
||||
- `1 <= n <= 5000`
|
||||
- `-5000 <= nums[i] <= 5000`
|
||||
- All the integers of `nums` are unique.
|
||||
- `nums` is sorted and rotated between 1 and `n` times.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["findMin(nums)"]) --> I["l = 0, r = n-1, lowest_index = -1"]
|
||||
I --> W{"l <= r?"}
|
||||
W -- no --> E(["return nums[lowest_index]"])
|
||||
W -- yes --> M["m = (l + r) // 2"]
|
||||
M --> C{"nums[m] <= nums[-1]?"}
|
||||
C -- yes --> A["in the right sorted run: record lowest_index = m, r = m - 1"]
|
||||
A --> W
|
||||
C -- no --> B["still in the left sorted run: l = m + 1"]
|
||||
B --> W
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def findMin(self, nums: List[int]) -> int:
|
||||
l, r = 0, len(nums) - 1
|
||||
lowest_index = -1
|
||||
|
||||
while l <= r:
|
||||
m = (l + r) // 2
|
||||
if nums[m] <= nums[-1]:
|
||||
lowest_index = m
|
||||
r = m - 1
|
||||
else:
|
||||
l = m + 1
|
||||
|
||||
return nums[lowest_index]
|
||||
```
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
---
|
||||
title: '162. Find Peak Element'
|
||||
description: A peak element is an element that is strictly greater than its neighbors
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/64"
|
||||
sidebar:
|
||||
label: 'Find Peak Element'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
You must write an algorithm that runs in O(log n) time.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,2,3,1]`
|
||||
- Output: `2`
|
||||
- Explanation: `3` is a peak element and your function should return the index number `2`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1,2,1,3,5,6,4]`
|
||||
- Output: `5`
|
||||
- Explanation: Your function can return either index number `1` where the peak element is `2`, or index number `5` where the peak element is `6`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 1000`
|
||||
- `-2^31 <= nums[i] <= 2^31 - 1`
|
||||
- `nums[i] != nums[i + 1] for all valid i.`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def findPeakElement(self, nums: list[int]) -> int:
|
||||
left, right = 0, len(nums) - 1
|
||||
while left < right:
|
||||
mid = (left + right) // 2
|
||||
if nums[mid] < nums[mid + 1]:
|
||||
left = mid + 1
|
||||
else:
|
||||
right = mid
|
||||
|
||||
return left
|
||||
```
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
---
|
||||
title: '33. Search in Rotated Sorted Array'
|
||||
description: There is an integer array nums sorted in ascending order (with distinct values)
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
video: "U8XENwh8Oy8"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/60"
|
||||
sidebar:
|
||||
label: 'Search in Rotated Sorted Array'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
You must write an algorithm with O(log n) runtime complexity.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [4,5,6,7,0,1,2], target = 0`
|
||||
- Output: `4`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [4,5,6,7,0,1,2], target = 3`
|
||||
- Output: `-1`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1], target = 0`
|
||||
- Output: `-1`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 5000`
|
||||
- `-10^4 <= nums[i] <= 10^4`
|
||||
- All values of `nums` are unique.
|
||||
- `nums` is an ascending array that is possibly rotated.
|
||||
- `-10^4 <= target <= 10^4`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["search(nums, target)"]) --> I["l = 0, r = n - 1"]
|
||||
I --> W{"l <= r?"}
|
||||
W -- no --> E(["return -1"])
|
||||
W -- yes --> M["mid = floor((l + r) / 2)"]
|
||||
M --> F{"nums[mid] == target?"}
|
||||
F -- yes --> R(["return mid"])
|
||||
F -- no --> H{"nums[l] <= nums[mid]? — left half sorted"}
|
||||
H -- yes --> A{"target outside [nums[l], nums[mid]]?"}
|
||||
A -- yes --> A1["l = mid + 1 — search the right half"]
|
||||
A -- no --> A2["r = mid - 1"]
|
||||
H -- no --> B{"target outside [nums[mid], nums[r]]?"}
|
||||
B -- yes --> B1["r = mid - 1 — search the left half"]
|
||||
B -- no --> B2["l = mid + 1"]
|
||||
A1 --> W
|
||||
A2 --> W
|
||||
B1 --> W
|
||||
B2 --> W
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} target
|
||||
* @return {number}
|
||||
*/
|
||||
var search = function(nums, target) {
|
||||
let l = 0, r = nums.length - 1;
|
||||
|
||||
while (l <= r){
|
||||
let mid = Math.floor((l + r)/2);
|
||||
if (target === nums[mid]) {
|
||||
return mid
|
||||
}
|
||||
|
||||
// Left sorted portion
|
||||
if (nums[l] <= nums[mid]){
|
||||
if (target > nums[mid] || target < nums[l]){
|
||||
l = mid + 1;
|
||||
}else{
|
||||
r = mid - 1;
|
||||
}
|
||||
}
|
||||
// Right sorted portion
|
||||
else{
|
||||
if(target < nums[mid] || target > nums[r]){
|
||||
r = mid - 1;
|
||||
}else{
|
||||
l = mid + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
```
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
---
|
||||
title: '34. Find First and Last Position of Element in Sorted Array'
|
||||
description: Given an array of integers nums sorted in non-decreasing order, find the starting and ending position of a given target value
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/65"
|
||||
sidebar:
|
||||
label: 'Find First and Last Position of Element in Sorted Array'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
You must write an algorithm with O(log n) runtime complexity.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [5,7,7,8,8,10], target = 8`
|
||||
- Output: `[3,4]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [5,7,7,8,8,10], target = 6`
|
||||
- Output: `[-1,-1]`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [], target = 0`
|
||||
- Output: `[-1,-1]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `0 <= nums.length <= 10^5`
|
||||
- `-10^9 <= nums[i] <= 10^9`
|
||||
- `nums` is a non-decreasing array.
|
||||
- `-10^9 <= target <= 10^9`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def searchRange(self, nums: list[int], target: int) -> list[int]:
|
||||
def find(first):
|
||||
result = -1
|
||||
left, right = 0, len(nums) - 1
|
||||
while left <= right:
|
||||
mid = (left + right) // 2
|
||||
if nums[mid] == target:
|
||||
result = mid
|
||||
if first:
|
||||
right = mid - 1
|
||||
else:
|
||||
left = mid + 1
|
||||
elif nums[mid] < target:
|
||||
left = mid + 1
|
||||
else:
|
||||
right = mid - 1
|
||||
return result
|
||||
|
||||
return [find(True), find(False)]
|
||||
```
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
---
|
||||
title: '35. Search Insert Position'
|
||||
description: Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
video: "K-RYzDZkzCI"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/63"
|
||||
sidebar:
|
||||
label: 'Search Insert Position'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
::::warning
|
||||
You must write an algorithm with O(log n) runtime complexity.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,3,5,6], target = 5`
|
||||
- Output: `2`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1,3,5,6], target = 2`
|
||||
- Output: `1`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1,3,5,6], target = 7`
|
||||
- Output: `4`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^4`
|
||||
- `-10^4 <= nums[i] <= 10^4`
|
||||
- `nums` contains distinct values sorted in ascending order.
|
||||
- `-10^4 <= target <= 10^4`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["searchInsert(nums, target)"]) --> I["l = 0, r = n - 1"]
|
||||
I --> W{"l <= r?"}
|
||||
W -- yes --> M["m = (l + r) // 2"]
|
||||
M --> Q{"nums[m] vs target"}
|
||||
Q -- equal --> R(["return m"])
|
||||
Q -- "nums[m] < target" --> L["l = m + 1"]
|
||||
L --> W
|
||||
Q -- "nums[m] > target" --> H["r = m - 1"]
|
||||
H --> W
|
||||
W -- no --> E(["return (l + r) // 2 + 1 — the insert slot"])
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def searchInsert(self, nums: List[int], target: int) -> int:
|
||||
l, r = 0, len(nums) - 1
|
||||
|
||||
while l <= r:
|
||||
m = (l + r) // 2
|
||||
if nums[m] == target:
|
||||
return m
|
||||
elif nums[m] < target:
|
||||
l = m + 1
|
||||
elif nums[m] > target:
|
||||
r = m - 1
|
||||
|
||||
return (l + r) // 2 + 1
|
||||
```
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
---
|
||||
title: '704. Binary Search'
|
||||
description: Given an array of integers nums which is sorted in ascending order, and an integer target, write a function to search target in nums. If target exists, then return its index. Otherwise, return -1
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
video: "s4DPM8ct1pI"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/58"
|
||||
sidebar:
|
||||
label: 'Binary Search'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
::::warning
|
||||
You must write an algorithm with O(log n) runtime complexity.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [-1,0,3,5,9,12], target = 9`
|
||||
- Output: `4`
|
||||
- Explanation: `9` exists in `nums` and its index is `4`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [-1,0,3,5,9,12], target = 2`
|
||||
- Output: `-1`
|
||||
- Explanation: `2` does not exist in `nums` so return `-1`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^4`
|
||||
- `-10^4 < nums[i], target < 10^4`
|
||||
- All the integers in `nums` are unique.
|
||||
- `nums` is sorted in ascending order.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["search(nums, target)"]) --> I["left = 0, right = n - 1"]
|
||||
I --> W{"left <= right?"}
|
||||
W -- no --> E(["return -1"])
|
||||
W -- yes --> M["mid = left + floor((right - left) / 2)"]
|
||||
M --> Q{"nums[mid] vs target"}
|
||||
Q -- equal --> R(["return mid"])
|
||||
Q -- "nums[mid] < target" --> L["left = mid + 1"]
|
||||
L --> W
|
||||
Q -- "nums[mid] > target" --> H["right = mid - 1"]
|
||||
H --> W
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} target
|
||||
* @return {number}
|
||||
*/
|
||||
var search = function(nums, target) {
|
||||
let left = 0;
|
||||
let right = nums.length - 1;
|
||||
|
||||
while(left <= right) {
|
||||
const mid = left + Math.floor((right - left) / 2);
|
||||
if (nums[mid] === target) {
|
||||
return mid;
|
||||
} else if(nums[mid] < target){
|
||||
left = mid + 1;
|
||||
} else if (nums[mid] > target) {
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
```
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
---
|
||||
title: '74. Search a 2D Matrix'
|
||||
description: 'You are given an m x n integer matrix matrix with the following two properties:'
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
- { name: "Matrix", slug: "matrix" }
|
||||
video: "Ber2pi2C0j0"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/61"
|
||||
sidebar:
|
||||
label: 'Search a 2D Matrix'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
You must write a solution in O(log(m * n)) time complexity.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3`
|
||||
- Output: `true`
|
||||
|
||||
### Example 2:
|
||||
- Input: `matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `m == matrix.length`
|
||||
- `n == matrix[i].length`
|
||||
- `1 <= m, n <= 100`
|
||||
- `-10^4 <= matrix[i][j], target <= 10^4`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["searchMatrix(matrix, target)"]) --> I["top = 0, bot = ROWS - 1"]
|
||||
I --> W1{"top <= bot?"}
|
||||
W1 -- yes --> R1["row = (top + bot) // 2"]
|
||||
R1 --> C1{"target vs that row's range"}
|
||||
C1 -- "above matrix[row][-1]" --> U["top = row + 1"]
|
||||
C1 -- "below matrix[row][0]" --> V["bot = row - 1"]
|
||||
C1 -- inside --> B(["break — row found"])
|
||||
U --> W1
|
||||
V --> W1
|
||||
W1 -- no --> F(["return False — no row can hold it"])
|
||||
B --> P["row = (top + bot) // 2; l = 0, r = COLS - 1"]
|
||||
P --> W2{"l <= r?"}
|
||||
W2 -- no --> G(["return False"])
|
||||
W2 -- yes --> M["m = (l + r) // 2"]
|
||||
M --> C2{"target vs matrix[row][m]"}
|
||||
C2 -- greater --> X["l = m + 1"]
|
||||
C2 -- smaller --> Y["r = m - 1"]
|
||||
C2 -- equal --> T(["return True"])
|
||||
X --> W2
|
||||
Y --> W2
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
|
||||
ROWS, COLS = len(matrix), len(matrix[0])
|
||||
|
||||
top, bot = 0, ROWS - 1
|
||||
while top <= bot:
|
||||
row = (top + bot) // 2
|
||||
if target > matrix[row][-1]:
|
||||
top = row + 1
|
||||
elif target < matrix[row][0]:
|
||||
bot = row - 1
|
||||
else:
|
||||
break
|
||||
|
||||
if not (top <= bot):
|
||||
return False
|
||||
|
||||
row = (top + bot) // 2
|
||||
l, r = 0, COLS - 1
|
||||
while l <= r:
|
||||
m = (l + r) // 2
|
||||
if target > matrix[row][m]:
|
||||
l = m + 1
|
||||
elif target < matrix[row][m]:
|
||||
r = m - 1
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
```
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
---
|
||||
title: '875. Koko Eating Bananas'
|
||||
description: Koko loves to eat bananas. There are n piles of bananas, the i^th pile has piles[i] bananas. The guards have gone and will come back in h hours
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
video: "U2SozAs9RzA"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/59"
|
||||
sidebar:
|
||||
label: 'Koko Eating Bananas'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `piles = [3,6,7,11], h = 8`
|
||||
- Output: `4`
|
||||
|
||||
### Example 2:
|
||||
- Input: `piles = [30,11,23,4,20], h = 5`
|
||||
- Output: `30`
|
||||
|
||||
### Example 3:
|
||||
- Input: `piles = [30,11,23,4,20], h = 6`
|
||||
- Output: `23`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= piles.length <= 10^4`
|
||||
- `piles.length <= h <= 10^9`
|
||||
- `1 <= piles[i] <= 10^9`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["minEatingSpeed(piles, h)"]) --> I["l = 1, r = max(piles)"]
|
||||
I --> W{"l < r?"}
|
||||
W -- no --> E(["return l — the smallest workable speed"])
|
||||
W -- yes --> M["mid = floor((l + r) / 2)"]
|
||||
M --> K["kWorks(mid): hours = sum of ceil(p / mid)"]
|
||||
K --> Q{"hours <= h?"}
|
||||
Q -- yes --> A["r = mid — keep mid, try slower"]
|
||||
Q -- no --> B["l = mid + 1 — too slow, speed up"]
|
||||
A --> W
|
||||
B --> W
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} piles
|
||||
* @param {number} h
|
||||
* @return {number}
|
||||
*/
|
||||
var minEatingSpeed = function(piles, h) {
|
||||
// Function to determine if K works for the H
|
||||
function kWorks(k){
|
||||
let hours = 0;
|
||||
for (let p of piles){
|
||||
hours += Math.ceil(p/k)
|
||||
}
|
||||
return hours <= h;
|
||||
}
|
||||
|
||||
// Setup Binary Search
|
||||
let l = 1;
|
||||
let r = Math.max(...piles);
|
||||
|
||||
// Find the K value which works for H and consumes all bananas
|
||||
while (l < r){
|
||||
const mid = Math.floor((l + r) / 2);
|
||||
if (kWorks(mid)){
|
||||
r = mid;
|
||||
}else{
|
||||
l = mid + 1;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
};
|
||||
```
|
||||
@@ -1,86 +0,0 @@
|
||||
---
|
||||
title: Binary Search
|
||||
description: 'Half of a sorted range is removed at each step until the target is found.'
|
||||
hidden: true
|
||||
---
|
||||
|
||||
Binary search is an efficient array search algorithm. It works by narrowing down the search range by half each time. If you have looked up a word in a physical dictionary, you've already used binary search in real life. Let's look at a simple example:
|
||||
|
||||
*Given a sorted array of integers and an integer called target, find the element that equals the target and return its index. If the element is not found, return -1.*
|
||||
|
||||
The key observation here is that the array is sorted. We pick a random element in the array and compare it to the target.
|
||||
|
||||
- If we happen to pick the element that equals the target (how lucky!), then bingo. We don't need to do any more work; we return its index.
|
||||
- If the element is smaller than the target, then we know the target cannot be found in the section to the left of the current element, since everything to the left is even smaller. So, we discard the current element and everything on the left from the search range.
|
||||
- If the element is larger than the target, then we know the target cannot be found in the section to the right of the current element, since everything to the right is even larger. So, we discard the current element and everything on the right from the search range.
|
||||
|
||||
We repeat this process until we find the target. Instead of picking a random element, we always pick the **middle** element in the current search range. This way, we can discard half of the options and shrink the search range by half each time. This gives us `O(log(N))` runtime.
|
||||
|
||||
This idea can be implemented both iteratively and recursively. However, the major difference is that the iterative version of binary search uses `O(1)` memory while the recursive version uses `O(log(N))` memory.
|
||||
|
||||
## Implementation
|
||||
|
||||
The search range is represented by the `left` and `right` indices that start from both ends of the array and move towards each other as we search. When moving the index, we discard elements and shrink the search range.
|
||||
|
||||
Time Complexity: `O(log(n))`
|
||||
|
||||
|
||||
<Carousel>
|
||||
<CarouselImage src='../../../public/binary_search.001.png' />
|
||||
<CarouselImage src='../../../public/binary_search.002.png' />
|
||||
<CarouselImage src='../../../public/binary_search.003.png' />
|
||||
<CarouselImage src='../../../public/binary_search.004.png' />
|
||||
<CarouselImage src='../../../public/binary_search.005.png' />
|
||||
<CarouselImage src='../../../public/binary_search.006.png' />
|
||||
<CarouselImage src='../../../public/binary_search.007.png' />
|
||||
<CarouselImage src='../../../public/binary_search.008.png' />
|
||||
</Carousel>
|
||||
|
||||
```python
|
||||
def binary_search(arr: list[int], target: int) -> int:
|
||||
left, right = 0, len(arr) - 1
|
||||
# <= because left and right could point to the same element, < would miss it
|
||||
while left <= right:
|
||||
# double slash for integer division in python 3,
|
||||
# we don't have to worry about integer `left + right` overflow
|
||||
# since python integers can be arbitrarily large
|
||||
mid = (left + right) // 2
|
||||
# found target, return its index
|
||||
if arr[mid] == target:
|
||||
return mid
|
||||
# middle less than target, discard left half by making left search boundary `mid + 1`
|
||||
if arr[mid] < target:
|
||||
left = mid + 1
|
||||
# middle greater than target, discard right half by making right search boundary `mid - 1`
|
||||
else:
|
||||
right = mid - 1
|
||||
return -1 # if we get here we didn't hit above return so we didn't find target
|
||||
```
|
||||
|
||||
### Calculating `mid`
|
||||
|
||||
Note that when calculating `mid`, if the number of elements is even, there are two elements in the middle. We usually follow the convention of picking the first one, equivalent to doing integer division `(left + right) / 2`.
|
||||
|
||||
In most programming languages, we calculate `mid` with `left + floor((right-left) / 2)` to avoid potential integer overflow. However, in Python, we do not need to worry about integer overflow with `left + right` because Python3 integers can be arbitrarily large.
|
||||
|
||||
## Deduction
|
||||
|
||||
It's essential to understand and deduce the algorithm yourself instead of memorizing it. In an actual interview, interviewers may ask you additional questions to test your understanding, so simply memorizing the algorithm may not be enough to convince the interviewer.
|
||||
|
||||
Key elements in writing a correct binary search:
|
||||
|
||||
### 1. When to terminate the loop
|
||||
|
||||
Make sure the `while` loop includes an equality comparison; otherwise, we might skip the loop and miss the potential match for the edge case of a one-element array.
|
||||
|
||||
### 2. Whether/how to update `left` and `right` boundary in the `if` conditions
|
||||
|
||||
Consider which side to discard. If `arr[mid]` is smaller than the `target`, we should discard everything on the left by making `left = mid + 1`.
|
||||
|
||||
### 3. Should I discard the current element?
|
||||
|
||||
For vanilla binary search, we can discard it since it cannot be the final answer if it is not equal to the target. There might be situations where you would want to think twice before discarding the current element. We'll discuss this in the next module.
|
||||
|
||||
## When to use binary search
|
||||
|
||||
Interestingly, binary search works beyond sorted arrays. **You can use binary search whenever you make a binary decision to shrink the search range.**
|
||||
@@ -1,3 +0,0 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Binary Search", order: 5, icon: "search", display: "page" });
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
---
|
||||
title: '128. Longest Consecutive Sequence'
|
||||
description: Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "Union-Find", slug: "union-find" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/34"
|
||||
sidebar:
|
||||
label: 'Longest Consecutive Sequence'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
You must write an algorithm that runs in O(n) time.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [100,4,200,1,3,2]`
|
||||
- Output: `4`
|
||||
- Explanation: The longest consecutive elements sequence is [1, `2`, `3`, 4]. Therefore its length is `4`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [0,3,7,2,5,8,4,6,0,1]`
|
||||
- Output: `9`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1,0,1,2]`
|
||||
- Output: `3`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `0 <= nums.length <= 10^5`
|
||||
- `-10^9 <= nums[i] <= 10^9`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def longestConsecutive(self, nums: list[int]) -> int:
|
||||
seen = set(nums)
|
||||
best = 0
|
||||
|
||||
for n in seen:
|
||||
if n - 1 in seen:
|
||||
continue
|
||||
|
||||
length = 1
|
||||
while length + n in seen:
|
||||
length += 1
|
||||
|
||||
best = max(length, best)
|
||||
|
||||
return best
|
||||
```
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
---
|
||||
title: '1832. Check if the Sentence Is Pangram'
|
||||
description: A pangram is a sentence where every letter of the English alphabet appears at least once
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "String", slug: "string" }
|
||||
sidebar:
|
||||
label: 'Check if the Sentence Is Pangram'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `sentence = "thequickbrownfoxjumpsoverthelazydog"`
|
||||
- Output: `true`
|
||||
- Explanation: `sentence` contains at least one of every letter of the English alphabet.
|
||||
|
||||
### Example 2:
|
||||
- Input: `sentence = "leetcode"`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= sentence.length <= 1000`
|
||||
- `sentence` consists of lowercase English letters.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["checkIfPangram(sentence)"]) --> I["freq = {}"]
|
||||
I --> L{"more char c?"}
|
||||
L -- yes --> C["freq[c] = (freq[c] or 0) + 1"]
|
||||
C --> L
|
||||
L -- no --> Q{"distinct keys in freq == 26?"}
|
||||
Q -- yes --> R(["return true"])
|
||||
Q -- no --> F(["return false"])
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string} sentence
|
||||
* @return {boolean}
|
||||
*/
|
||||
var checkIfPangram = function(sentence) {
|
||||
const freq = {};
|
||||
for (let c of sentence) freq[c] = (freq[c] || 0) + 1;
|
||||
|
||||
if (Object.keys(freq).length === 26){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
```
|
||||
@@ -1,65 +0,0 @@
|
||||
---
|
||||
title: '1. Two Sum'
|
||||
description: You are given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
video: "KLlXCFG5TnA"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/29"
|
||||
sidebar:
|
||||
label: 'Two Sum'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
::::warning
|
||||
Can you come up with an algorithm that is less than O(n^2) time complexity?
|
||||
::::
|
||||
|
||||
### 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.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["twoSum(nums, target)"]) --> I["seen = {} — value to index"]
|
||||
I --> L{"more (i, num) in nums?"}
|
||||
L -- no --> E(["return []"])
|
||||
L -- yes --> C["complement = target - num"]
|
||||
C --> H{"complement in seen?"}
|
||||
H -- yes --> R(["return [seen[complement], i]"])
|
||||
H -- no --> W["seen[num] = i"]
|
||||
W --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def twoSum(self, nums: List[int], target: int) -> List[int]:
|
||||
seen = {}
|
||||
for i, num in enumerate(nums):
|
||||
complement = target - num
|
||||
if complement in seen:
|
||||
return [seen[complement], i]
|
||||
seen[num] = i
|
||||
return []
|
||||
```
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
---
|
||||
title: '205. Isomorphic Strings'
|
||||
description: Given two strings s and t, determine if they are isomorphic
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "String", slug: "string" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/33"
|
||||
sidebar:
|
||||
label: 'Isomorphic Strings'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "egg", t = "add"`
|
||||
- Output: `true`
|
||||
- Explanation: The strings `s` and `t` can be made identical by: • Mapping 'e' to 'a'. • Mapping 'g' to 'd'.
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "f11", t = "b23"`
|
||||
- Output: `false`
|
||||
- Explanation: The strings `s` and `t` can not be made identical as `'1`' needs to be mapped to both `'2`' and `'3`'.
|
||||
|
||||
### Example 3:
|
||||
- Input: `s = "paper", t = "title"`
|
||||
- Output: `true`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 5 * 10^4`
|
||||
- `t.length == s.length`
|
||||
- `s` and `t` consist of any valid ascii character.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def isIsomorphic(self, s: str, t: str) -> bool:
|
||||
N = len(t)
|
||||
seen = {}
|
||||
|
||||
for i in range(N):
|
||||
c1, c2 = s[i], t[i]
|
||||
if c1 in seen and seen[c1] != c2:
|
||||
return False
|
||||
elif c1 in seen and seen[c1] == c2:
|
||||
continue
|
||||
else:
|
||||
seen[c1] = c2
|
||||
|
||||
return len(set(s)) == len(set(t))
|
||||
```
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
---
|
||||
title: '217. Contains Duplicate'
|
||||
description: Given an integer array nums, return true if any value appears at least twice in the array, and return false if every element is distinct
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "Sorting", slug: "sorting" }
|
||||
video: "3OamzN90kPg"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/27"
|
||||
sidebar:
|
||||
label: 'Contains Duplicate'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,2,3,1]`
|
||||
- Output: `true`
|
||||
- Explanation: The element `1` occurs at the indices `0` and `3`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1,2,3,4]`
|
||||
- Output: `false`
|
||||
- Explanation: All elements are distinct.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1,1,1,3,3,4,3,2,4,2]`
|
||||
- Output: `true`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^5`
|
||||
- `-10^9 <= nums[i] <= 10^9`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["containsDuplicate(nums)"]) --> I["freq = {}"]
|
||||
I --> L{"more n in nums?"}
|
||||
L -- no --> E(["return false"])
|
||||
L -- yes --> C["freq[n] = (freq[n] or 0) + 1"]
|
||||
C --> Q{"freq[n] >= 2?"}
|
||||
Q -- yes --> R(["return true"])
|
||||
Q -- no --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def containsDuplicate(self, nums: List[int]) -> bool:
|
||||
return len(set(nums)) != len(nums)
|
||||
```
|
||||
@@ -1,66 +0,0 @@
|
||||
---
|
||||
title: '242. Valid Anagram'
|
||||
description: Given two strings s and t, return true if t is an anagram of s, and false otherwise
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "String", slug: "string" }
|
||||
- { name: "Sorting", slug: "sorting" }
|
||||
video: "9UtInBqnCgA"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/28"
|
||||
sidebar:
|
||||
label: 'Valid Anagram'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
::::warning
|
||||
What if the inputs contain Unicode characters? How would you adapt your solution to such a case?
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "anagram", t = "nagaram"`
|
||||
- Output: `true`
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "rat", t = "car"`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length, t.length <= 5 * 10^4`
|
||||
- `s` and `t` consist of lowercase English letters.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["isAnagram(s, t)"]) --> I["freq: count every char of s"]
|
||||
I --> L{"more char c in t?"}
|
||||
L -- no --> E(["return true"])
|
||||
L -- yes --> Q{"freq[c] missing or 0?"}
|
||||
Q -- yes --> R(["return false — t has a char s cannot cover"])
|
||||
Q -- no --> D["freq[c] -= 1"]
|
||||
D --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string} s
|
||||
* @param {string} t
|
||||
* @return {boolean}
|
||||
*/
|
||||
var isAnagram = function(s, t) {
|
||||
let freq = {};
|
||||
for (let c of s) freq[c] = (freq[c] || 0) + 1;
|
||||
|
||||
for (let c of t) {
|
||||
if(!freq[c] || freq[c] === 0){
|
||||
return false;
|
||||
}
|
||||
freq[c] = freq[c] - 1;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
```
|
||||
@@ -1,57 +0,0 @@
|
||||
---
|
||||
title: '290. Word Pattern'
|
||||
description: Given a pattern and a string s, find if s follows the same pattern
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "String", slug: "string" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/35"
|
||||
sidebar:
|
||||
label: 'Word Pattern'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `pattern = "abba", s = "dog cat cat dog"`
|
||||
- Output: `true`
|
||||
- Explanation: The bijection can be established as: • 'a' maps to "dog". • 'b' maps to "cat".
|
||||
|
||||
### Example 2:
|
||||
- Input: `pattern = "abba", s = "dog cat cat fish"`
|
||||
- Output: `false`
|
||||
|
||||
### Example 3:
|
||||
- Input: `pattern = "aaaa", s = "dog cat cat dog"`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= pattern.length <= 300`
|
||||
- `pattern` contains only lower-case English letters.
|
||||
- `1 <= s.length <= 3000`
|
||||
- `s` contains only lowercase English letters and spaces ' '.
|
||||
- `s` does not contain any leading or trailing spaces.
|
||||
- All the words in `s` are separated by a single space.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def wordPattern(self, pattern: str, s: str) -> bool:
|
||||
if len(pattern) != len(s.split()):
|
||||
return False
|
||||
|
||||
words = s.split()
|
||||
map = {}
|
||||
|
||||
for i in range(len(pattern)):
|
||||
c = pattern[i]
|
||||
w = words[i]
|
||||
|
||||
if c in map and map[c] != w:
|
||||
return False
|
||||
else:
|
||||
map[c] = w
|
||||
|
||||
return len(set(pattern)) == len(set(words))
|
||||
```
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
---
|
||||
title: '347. Top K Frequent Elements'
|
||||
description: Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "Divide and Conquer", slug: "divide-and-conquer" }
|
||||
- { name: "Sorting", slug: "sorting" }
|
||||
- { name: "Heap (Priority Queue)", slug: "heap-priority-queue" }
|
||||
- { name: "Bucket Sort", slug: "bucket-sort" }
|
||||
- { name: "Counting", slug: "counting" }
|
||||
- { name: "Quickselect", slug: "quickselect" }
|
||||
video: "YPTqKIgVk-k"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/31"
|
||||
sidebar:
|
||||
label: 'Top K Frequent Elements'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,1,1,2,2,3], k = 2`
|
||||
- Output: `[1,2]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1], k = 1`
|
||||
- Output: `[1]`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1,2,1,2,1,2,3,1,3,2], k = 2`
|
||||
- Output: `[1,2]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^5`
|
||||
- `-10^4 <= nums[i] <= 10^4`
|
||||
- `k` is in the range `[1, the number of unique elements in the array]`.
|
||||
- It is guaranteed that the answer is unique.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["topKFrequent(nums, k)"]) --> F["freq: count every value in nums"]
|
||||
F --> K["keys of freq, cast to Number"]
|
||||
K --> O["sort by freq[b] - freq[a] — most frequent first"]
|
||||
O --> R(["return slice(0, k)"])
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} k
|
||||
* @return {number[]}
|
||||
*/
|
||||
var topKFrequent = function (nums, k) {
|
||||
const freq = {};
|
||||
for (let n of nums) freq[n] = (freq[n] || 0) + 1;
|
||||
|
||||
return Object.keys(freq)
|
||||
.map(Number)
|
||||
.sort((a, b) => freq[b] - freq[a])
|
||||
.slice(0, k);
|
||||
};
|
||||
```
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
---
|
||||
title: '387. First Unique Character in a String'
|
||||
description: Given a string s, find the first non-repeating character in it and return its index. If it does not exist, return -1
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "String", slug: "string" }
|
||||
- { name: "Queue", slug: "queue" }
|
||||
- { name: "Counting", slug: "counting" }
|
||||
video: "rBENYgWy3xU"
|
||||
sidebar:
|
||||
label: 'First Unique Character in a String'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "leetcode"`
|
||||
- Output: `0`
|
||||
- Explanation: The character `'l'` at index `0` is the first character that does not occur at any other index.
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "loveleetcode"`
|
||||
- Output: `2`
|
||||
|
||||
### Example 3:
|
||||
- Input: `s = "aabb"`
|
||||
- Output: `-1`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 10^5`
|
||||
- `s` consists of only lowercase English letters.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["firstUniqChar(s)"]) --> F["Pass 1 — freq: count every char of s"]
|
||||
F --> L{"Pass 2 — more i in 0..len-1?"}
|
||||
L -- no --> E(["return -1"])
|
||||
L -- yes --> Q{"freq[s[i]] == 1?"}
|
||||
Q -- yes --> R(["return i — leftmost wins because the scan is in order"])
|
||||
Q -- no --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string} s
|
||||
* @return {number}
|
||||
*/
|
||||
var firstUniqChar = function (s) {
|
||||
const freq = {};
|
||||
for (let c of s) freq[c] = (freq[c] || 0) + 1;
|
||||
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
if (freq[s[i]] === 1) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
```
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
---
|
||||
title: '451. Sort Characters By Frequency'
|
||||
description: Given a string s, sort it in decreasing order based on the frequency of the characters. The frequency of a character is the number of times it appears in the string
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "String", slug: "string" }
|
||||
- { name: "Sorting", slug: "sorting" }
|
||||
- { name: "Heap (Priority Queue)", slug: "heap-priority-queue" }
|
||||
- { name: "Bucket Sort", slug: "bucket-sort" }
|
||||
- { name: "Counting", slug: "counting" }
|
||||
video: "OXdXc9HTrIg"
|
||||
sidebar:
|
||||
label: 'Sort Characters By Frequency'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "tree"`
|
||||
- Output: `"eert"`
|
||||
- Explanation: `'e'` appears twice while `'r'` and `'t'` both appear once. So `'e'` must appear before both `'r'` and `'t'`. Therefore `"eetr"` is also a valid answer.
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "cccaaa"`
|
||||
- Output: `"aaaccc"`
|
||||
- Explanation: Both `'c'` and `'a'` appear three times, so both `"cccaaa"` and `"aaaccc"` are valid answers. Note that `"cacaca"` is incorrect, as the same characters must be together.
|
||||
|
||||
### Example 3:
|
||||
- Input: `s = "Aabb"`
|
||||
- Output: `"bbAa"`
|
||||
- Explanation: `"bbaA"` is also a valid answer, but `"Aabb"` is incorrect. Note that `'A'` and `'a'` are treated as two different characters.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 5 * 10^5`
|
||||
- `s` consists of uppercase and lowercase English letters and digits.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["frequencySort(s)"]) --> F["freq: count every char of s"]
|
||||
F --> C["split s and sort with a two-key comparator"]
|
||||
C --> K1["primary: freq[b] - freq[a] — most frequent first"]
|
||||
C --> K2["tie-break: a.localeCompare(b) — alphabetical"]
|
||||
K1 --> R(["join and return"])
|
||||
K2 --> R
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string} s
|
||||
* @return {string}
|
||||
*/
|
||||
var frequencySort = function (s) {
|
||||
// count the frequency of each character
|
||||
const freq = {};
|
||||
for (let c of s) freq[c] = (freq[c] || 0) + 1;
|
||||
|
||||
// sort the characters by frequency
|
||||
return s
|
||||
.split("")
|
||||
.sort((a, b) => freq[b] - freq[a] || a.localeCompare(b))
|
||||
.join("");
|
||||
};
|
||||
```
|
||||
@@ -1,72 +0,0 @@
|
||||
---
|
||||
title: '49. Group Anagrams'
|
||||
description: Given an array of strings strs, group the anagrams together. You can return the answer in any order
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "String", slug: "string" }
|
||||
- { name: "Sorting", slug: "sorting" }
|
||||
video: "vzdNOK2oB2E"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/30"
|
||||
sidebar:
|
||||
label: 'Group Anagrams'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `strs = ["eat","tea","tan","ate","nat","bat"]`
|
||||
- Output: `[["bat"],["nat","tan"],["ate","eat","tea"]]`
|
||||
- Explanation: There is no string in `strs` that can be rearranged to form `"bat"`. The strings `"nat"` and `"tan"` are anagrams as they can be rearranged to form each other. The strings `"ate"`, `"eat"`, and `"tea"` are anagrams as they can be rearranged to form each other.
|
||||
|
||||
### Example 2:
|
||||
- Input: `strs = [""]`
|
||||
- Output: `[[""]]`
|
||||
|
||||
### Example 3:
|
||||
- Input: `strs = ["a"]`
|
||||
- Output: `[["a"]]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= strs.length <= 10^4`
|
||||
- `0 <= strs[i].length <= 100`
|
||||
- `strs[i]` consists of lowercase English letters.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["groupAnagrams(strs)"]) --> K["sorted[i] = letters of strs[i], sorted — the anagram key"]
|
||||
K --> I["anagrams = {}"]
|
||||
I --> L{"more i in 0..n-1?"}
|
||||
L -- no --> E(["return Object.values(anagrams)"])
|
||||
L -- yes --> Q{"anagrams has sorted[i]?"}
|
||||
Q -- no --> N["anagrams[sorted[i]] = [strs[i]]"]
|
||||
Q -- yes --> P["anagrams[sorted[i]].push(strs[i])"]
|
||||
N --> L
|
||||
P --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string[]} strs
|
||||
* @return {string[][]}
|
||||
*/
|
||||
var groupAnagrams = function(strs) {
|
||||
let sorted = strs.map(str => str.split("").sort().join(""));
|
||||
let anagrams = {};
|
||||
|
||||
for (let i = 0; i < strs.length; i++){
|
||||
if(!anagrams[sorted[i]]){
|
||||
anagrams[sorted[i]] = [strs[i]]
|
||||
}else{
|
||||
anagrams[sorted[i]].push(strs[i])
|
||||
}
|
||||
}
|
||||
|
||||
return Object.values(anagrams);
|
||||
};
|
||||
```
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
title: Hash Table
|
||||
description: 'A key maps to a value in constant time, which removes the need for a full scan.'
|
||||
hidden: true
|
||||
---
|
||||
|
||||
Sometimes when programming, we need a data structure that maps an arbitrary data type to another arbitrary data type, like an array with non-integer indices. For example, a phone book that allows lookup by a person's name requires such data type.
|
||||
|
||||
A **hash table** (or a hash map) is one way of representing this data structure. The idea of hash table is this:
|
||||
|
||||
Data is stored in a fix-sized array, where each data value has an unique index. When we add a new `(key, value)` pair to the array, we use a hash function to generate a hash value within the range of the array with the `key`. We then store the data `value` at the index indicated by the generated hash value. Later, when we retrieve the data with the `key` from the hash table, we hash the `key` again and look up the data in the array with the corresponding index. Since the hash function always returns the same hash values with the same input, we will always find the correct item in that index.
|
||||
|
||||
|
||||
<Frame caption="Hash Table Operations">
|
||||
|
||||

|
||||
|
||||
</Frame>
|
||||
|
||||
|
||||
## Efficiency
|
||||
|
||||
Assuming the hash function uses constant time, the average time complexity is `O(n / k)` for each insertion/access operation on the table, where `n` is the number of entries in the hash table and `k` is the array size of the table. This assumes the hash function distributes keys uniformly across the `k` buckets, so each bucket holds about `n / k` entries on average.
|
||||
|
||||
### Frequency Counting
|
||||
|
||||
```python
|
||||
def get_counter(arr: list[int]) -> dict[int, int]:
|
||||
# initialize a hash map to store each number and its count
|
||||
counter: dict[int, int] = {}
|
||||
for num in arr:
|
||||
# check if num is a key in the hash map
|
||||
if num in counter:
|
||||
# update the count of num to increase by 1
|
||||
counter[num] += 1
|
||||
else:
|
||||
# set the count of num to 1
|
||||
counter[num] = 1
|
||||
return counter
|
||||
```
|
||||
|
||||
::: tip[Python provides a built-in `collections.Counter` class]
|
||||
```python
|
||||
from collections import Counter
|
||||
|
||||
fq = Counter(arr)
|
||||
```
|
||||
:::
|
||||
@@ -1,3 +0,0 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Hash Table", order: 1, icon: "hash", display: "page" });
|
||||
@@ -1,3 +0,0 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "1. Linear Structures", order: 1 });
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
---
|
||||
title: '739. Daily Temperatures'
|
||||
description: Given an array of integers temperatures represents the daily temperatures, return an array answer such that answer[i] is the number of days you have to wait after the i^th day to get a warmer temperature. If there is no future day for which this is possible, keep answer[i] == 0 instead
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Stack", slug: "stack" }
|
||||
- { name: "Monotonic Stack", slug: "monotonic-stack" }
|
||||
video: "cTBiBSnjO3c"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/72"
|
||||
sidebar:
|
||||
label: 'Daily Temperatures'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `temperatures = [73,74,75,71,69,72,76,73]`
|
||||
- Output: `[1,1,4,2,1,1,0,0]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `temperatures = [30,40,50,60]`
|
||||
- Output: `[1,1,1,0]`
|
||||
|
||||
### Example 3:
|
||||
- Input: `temperatures = [30,60,90]`
|
||||
- Output: `[1,1,0]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= temperatures.length <= 10^5`
|
||||
- `30 <= temperatures[i] <= 100`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["dailyTemperatures(temperatures)"]) --> I["ans = zeros(n), stack = [] — indices of days still waiting"]
|
||||
I --> L{"more (i, temp)?"}
|
||||
L -- no --> E(["return ans"])
|
||||
L -- yes --> W{"stack non-empty and temperatures[stack[-1]] < temp?"}
|
||||
W -- yes --> P["prev = stack.pop(); ans[prev] = i - prev — today resolves that day"]
|
||||
P --> W
|
||||
W -- no --> A["stack.append(i)"]
|
||||
A --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
|
||||
ans = [0] * len(temperatures)
|
||||
stack = []
|
||||
for i, temp in enumerate(temperatures):
|
||||
while stack and temperatures[stack[-1]] < temp:
|
||||
prev = stack.pop()
|
||||
ans[prev] = i - prev
|
||||
stack.append(i)
|
||||
return ans
|
||||
```
|
||||
@@ -1,69 +0,0 @@
|
||||
---
|
||||
title: '853. Car Fleet'
|
||||
description: There are n cars at given miles away from the starting mile 0, traveling to reach the mile target
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Stack", slug: "stack" }
|
||||
- { name: "Sorting", slug: "sorting" }
|
||||
- { name: "Monotonic Stack", slug: "monotonic-stack" }
|
||||
video: "Pr6T-3yB9RM"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/73"
|
||||
sidebar:
|
||||
label: 'Car Fleet'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `target = 12, position = [10,8,0,5,3], speed = [2,4,1,1,3]`
|
||||
- Output: `3`
|
||||
- Explanation: • The cars starting at `10 (speed 2`) and `8 (speed 4`) become a fleet, meeting each other at `12`. The fleet forms at `target`. • The car starting at `0 (speed 1`) does not catch up to any other car, so it is a fleet by itself. • The cars starting at `5 (speed 1`) and `3 (speed 3`) become a fleet, meeting each other at `6`. The fleet moves at `speed 1` until it reaches `target`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `target = 10, position = [3], speed = [3]`
|
||||
- Output: `1`
|
||||
- Explanation: There is only one car, hence there is only one fleet.
|
||||
|
||||
### Example 3:
|
||||
- Input: `target = 100, position = [0,2,4], speed = [4,2,1]`
|
||||
- Output: `1`
|
||||
- Explanation: • The cars starting at `0 (speed 4`) and `2 (speed 2`) become a fleet, meeting each other at `4`. The car starting at `4 (speed 1`) travels to `5`. • Then, the fleet at `4 (speed 2`) and the car at `position 5 (speed 1`) become one fleet, meeting each other at `6`. The fleet moves at `speed 1` until it reaches `target`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == position.length == speed.length`
|
||||
- `1 <= n <= 10^5`
|
||||
- `0 < target <= 10^6`
|
||||
- `0 <= position[i] < target`
|
||||
- All the values of `position` are unique.
|
||||
- `0 < speed[i] <= 10^6`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["carFleet(target, position, speed)"]) --> O["zip and sort by position, descending — nearest the target first"]
|
||||
O --> I["stack = [] — arrival time of each fleet's leader"]
|
||||
I --> L{"more (pos, spd)?"}
|
||||
L -- no --> E(["return len(stack) — one entry per fleet"])
|
||||
L -- yes --> T["time = (target - pos) / spd"]
|
||||
T --> Q{"stack empty or time > stack[-1]?"}
|
||||
Q -- yes --> A["stack.append(time) — slower, so it starts a new fleet"]
|
||||
Q -- no --> B["discard — it catches the car ahead and joins that fleet"]
|
||||
A --> L
|
||||
B --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def carFleet(self, target: int, position: List[int], speed: List[int]) -> int:
|
||||
stack = []
|
||||
for pos, spd in sorted(zip(position, speed), reverse=True):
|
||||
time = (target - pos) / spd
|
||||
if not stack or time > stack[-1]:
|
||||
stack.append(time)
|
||||
|
||||
return len(stack)
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Monotonic Stack
|
||||
description: 'A stack keeps its items in sorted order, which finds the next larger or smaller item in one pass.'
|
||||
hidden: true
|
||||
---
|
||||
@@ -1,3 +0,0 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Monotonic Stack", order: 7, icon: "trending-up", display: "page" });
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
---
|
||||
title: '238. Product of Array Except Self'
|
||||
description: Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i]
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Prefix Sum", slug: "prefix-sum" }
|
||||
video: "bNvIQI2wAjk"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/37"
|
||||
sidebar:
|
||||
label: 'Product of Array Except Self'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
You must write an algorithm that runs in O(n) time and without using the division operation.
|
||||
Can you solve the problem in O(1) extra space complexity? (The output array does not count as extra space for space complexity analysis.)
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,2,3,4]`
|
||||
- Output: `[24,12,8,6]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [-1,1,0,-3,3]`
|
||||
- Output: `[0,0,9,0,0]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `2 <= nums.length <= 10^5`
|
||||
- `-30 <= nums[i] <= 30`
|
||||
- The input is generated such that `answer[i]` is guaranteed to fit in a 32-bit integer.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["productExceptSelf(nums)"]) --> I["answer = ones(n), rightArr = ones(n)"]
|
||||
I --> P1["Pass 1 — left to right: answer[i] = nums[i-1] * answer[i-1]"]
|
||||
P1 --> P2["Pass 2 — right to left: rightArr[i] = nums[i+1] * rightArr[i+1]"]
|
||||
P2 --> P3["Pass 3: answer[i] *= rightArr[i]"]
|
||||
P3 --> E(["return answer — no division needed"])
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @return {number[]}
|
||||
*/
|
||||
var productExceptSelf = function(nums) {
|
||||
const n = nums.length;
|
||||
const answer = new Array(n).fill(1);
|
||||
const rightArr = new Array(n).fill(1);
|
||||
|
||||
for (let i = 1; i < n; i++) {
|
||||
answer[i] = nums[i - 1] * answer[i - 1];
|
||||
}
|
||||
for (let i = n - 2; i >= 0; i--) {
|
||||
rightArr[i] = nums[i + 1] * rightArr[i + 1];
|
||||
}
|
||||
for (let i = 0; i < n; i++) {
|
||||
answer[i] *= rightArr[i];
|
||||
}
|
||||
return answer;
|
||||
};
|
||||
```
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
---
|
||||
title: '303. Range Sum Query - Immutable'
|
||||
description: Given an integer array nums, handle multiple queries of the following type
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Design", slug: "design" }
|
||||
- { name: "Prefix Sum", slug: "prefix-sum" }
|
||||
video: "2pndAmo_sMA"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/36"
|
||||
sidebar:
|
||||
label: 'Range Sum Query - Immutable'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `["NumArray", "sumRange", "sumRange", "sumRange"]` `[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]`
|
||||
- Output: `[null, 1, -1, -3]`
|
||||
- Explanation: `NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);` `numArray.sumRange(0, 2); // return (-2) + 0 + 3 = 1` `numArray.sumRange(2, 5); // return 3 + (-5) + 2 + (-1) = -1` `numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^4`
|
||||
- `-10^5 <= nums[i] <= 10^5`
|
||||
- `0 <= left <= right < nums.length`
|
||||
- At most `10^4` calls will be made to `sumRange`.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph build["constructor(nums) — O(n) once"]
|
||||
A["prefix = [0]"] --> B{"more n in nums?"}
|
||||
B -- yes --> C["prefix.push(last + n)"]
|
||||
C --> B
|
||||
end
|
||||
build --> Q
|
||||
subgraph Q["sumRange(left, right) — O(1) per call"]
|
||||
D(["return prefix[right + 1] - prefix[left]"])
|
||||
end
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
*/
|
||||
class NumArray {
|
||||
constructor(nums) {
|
||||
this.prefix = [0];
|
||||
for (let n of nums){
|
||||
this.prefix.push(this.prefix[this.prefix.length - 1] + n);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {number} left
|
||||
* @param {number} right
|
||||
* @return {number}
|
||||
*/
|
||||
sumRange(left, right) {
|
||||
return this.prefix[right + 1] - this.prefix[left];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Your NumArray object will be instantiated and called as such:
|
||||
* var obj = new NumArray(nums)
|
||||
* var param_1 = obj.sumRange(left,right)
|
||||
*/
|
||||
```
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
---
|
||||
title: '525. Contiguous Array'
|
||||
description: Given a binary array nums, return the maximum length of a contiguous subarray with an equal number of 0 and 1
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "Prefix Sum", slug: "prefix-sum" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/39"
|
||||
sidebar:
|
||||
label: 'Contiguous Array'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [0,1]`
|
||||
- Output: `2`
|
||||
- Explanation: [0, 1] is the longest contiguous subarray with an equal number of `0` and `1`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [0,1,0]`
|
||||
- Output: `2`
|
||||
- Explanation: [0, 1] (or [1, 0]) is a longest contiguous subarray with equal number of `0` and `1`.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [0,1,1,1,1,1,0,0,0]`
|
||||
- Output: `6`
|
||||
- Explanation: `[1,1,1,0,0,0]` is the longest contiguous subarray with equal number of `0` and `1`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^5`
|
||||
- `nums[i]` is either 0 or 1.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def findMaxLength(self, nums: List[int]) -> int:
|
||||
map = {0: -1}
|
||||
count = 0
|
||||
longest = 0
|
||||
|
||||
for i, num in enumerate(nums):
|
||||
count += 1 if num == 1 else -1
|
||||
|
||||
if count in map:
|
||||
longest = max(longest, i - map[count])
|
||||
else:
|
||||
map[count] = i
|
||||
|
||||
return longest
|
||||
```
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
---
|
||||
title: '560. Subarray Sum Equals K'
|
||||
description: Given an array of integers nums and an integer k, return the total number of subarrays whose sum equals to k
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "Prefix Sum", slug: "prefix-sum" }
|
||||
video: "fFVZt-6sgyo"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/38"
|
||||
sidebar:
|
||||
label: 'Subarray Sum Equals K'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,1,1], k = 2`
|
||||
- Output: `2`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1,2,3], k = 3`
|
||||
- Output: `2`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 2 * 10^4`
|
||||
- `-1000 <= nums[i] <= 1000`
|
||||
- `-10^7 <= k <= 10^7`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["subarraySum(nums, k)"]) --> I["map = {0: 1} — the empty prefix; sum = 0, count = 0"]
|
||||
I --> L{"more n in nums?"}
|
||||
L -- no --> E(["return count"])
|
||||
L -- yes --> A["sum += n"]
|
||||
A --> Q{"map has sum - k?"}
|
||||
Q -- yes --> C["count += map.get(sum - k) — every earlier prefix that closes a window"]
|
||||
Q -- no --> W["map.set(sum, count of sum + 1)"]
|
||||
C --> W
|
||||
W --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} k
|
||||
* @return {number}
|
||||
*/
|
||||
var subarraySum = function(nums, k) {
|
||||
const map = new Map();
|
||||
map.set(0, 1);
|
||||
|
||||
let sum = 0;
|
||||
let count = 0;
|
||||
|
||||
for (let n of nums){
|
||||
sum += n;
|
||||
|
||||
if(map.has(sum - k)){
|
||||
count += map.get(sum - k);
|
||||
}
|
||||
|
||||
map.set(sum, (map.get(sum) || 0) + 1);
|
||||
}
|
||||
return count
|
||||
};
|
||||
```
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
---
|
||||
title: '974. Subarray Sums Divisible by K'
|
||||
description: Given an integer array nums and an integer k, return the number of non-empty subarrays that have a sum divisible by k
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "Prefix Sum", slug: "prefix-sum" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/40"
|
||||
sidebar:
|
||||
label: 'Subarray Sums Divisible by K'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [4,5,0,-2,-3,1], k = 5`
|
||||
- Output: `7`
|
||||
- Explanation: There are `7` subarrays with a sum divisible by `k = 5`: [4, `5`, `0`, `-2`, `-3`, 1], `[5]`, [5, 0], [5, `0`, `-2`, -3], `[0]`, [0, `-2`, -3], [-2, -3]
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [5], k = 9`
|
||||
- Output: `0`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 3 * 10^4`
|
||||
- `-10^4 <= nums[i] <= 10^4`
|
||||
- `2 <= k <= 10^4`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def subarraysDivByK(self, nums: list[int], k: int) -> int:
|
||||
remainder_counts = {0: 1}
|
||||
cur_sum = 0
|
||||
count = 0
|
||||
|
||||
for n in nums:
|
||||
cur_sum += n
|
||||
remainder = cur_sum % k
|
||||
|
||||
if remainder in remainder_counts:
|
||||
count += remainder_counts[remainder]
|
||||
|
||||
remainder_counts[remainder] = remainder_counts.get(remainder, 0) + 1
|
||||
|
||||
return count
|
||||
```
|
||||
@@ -1,45 +0,0 @@
|
||||
---
|
||||
title: Prefix Sum
|
||||
description: 'A running total is stored at each index, so the sum of any range is one subtraction.'
|
||||
hidden: true
|
||||
---
|
||||
|
||||
Suppose you are handed an array and asked for the sum of the elements between index `i` and index `j`. One query is easy: loop from `i` to `j` and add. But now imagine thousands of such queries over the same array, or a search that inspects the sum of every possible subarray. Recomputing each range from scratch costs `O(n)` per query, and the work piles up fast.
|
||||
|
||||
Prefix sum removes that repetition. You spend `O(n)` once to precompute running totals, and afterward every range sum collapses into a single subtraction that runs in `O(1)`, no matter how wide the range.
|
||||
|
||||
<YouTube id="CRVxUgmIO8M" title="Prefix Sum Explained" />
|
||||
|
||||
## Transformation
|
||||
|
||||
A prefix sum turns an array into a new array of running totals. For an input array `arr` of length `n`, build a `prefix` array of length `n + 1`:
|
||||
|
||||
`prefix[0] = 0`
|
||||
|
||||
`prefix[k] = arr[0] + arr[1] + ... + arr[k-1]`
|
||||
|
||||
Each entry is the previous total plus one more element, so a single pass builds the whole thing:
|
||||
|
||||
`prefix[k] = prefix[k-1] + arr[k-1]`
|
||||
|
||||
The leading `prefix[0] = 0` is the sum of zero elements. That extra slot is what makes the range math below land exactly on the boundaries, which is why `prefix` has one more cell than `arr`.
|
||||
|
||||
|
||||
<Frame caption="Each bar is the running total up to that index. Every step keeps the previous total (blue) and adds one new element (amber)" hint="">
|
||||
|
||||

|
||||
|
||||
|
||||
</Frame>
|
||||
|
||||
## Any range sum is one subtraction
|
||||
|
||||
The sum of the subarray from index `i` up to (but not including) `j` is `prefix[j] - prefix[i]`. `prefix[j]` is the total of everything before `j`, and `prefix[i]` is the total of everything before `i`, so subtracting throws away the front you did not ask for and leaves the middle.
|
||||
|
||||
## Watch the boundaries
|
||||
|
||||
The one place prefix sums trip people up is the off-by-one at the edges. Keep three facts straight: `prefix` has length `n + 1`, `prefix[0]` is `0`, and `sum(arr[i..j-1]) = prefix[j] - prefix[i]` uses an exclusive right index `j`. If a problem hands you an inclusive right index `r`, translate it to `prefix[r + 1] - prefix[i]`.
|
||||
|
||||
## When to reach for it
|
||||
|
||||
Prefix sums fit whenever you need repeated range sums over a fixed array, or when an algorithm searches across subarray boundaries. For a single one-off sum, a plain loop is simpler; the prefix array earns its `O(n)` setup only once the same array is queried many times.
|
||||
@@ -1,3 +0,0 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Prefix Sum", order: 2, icon: "sigma", display: "page" });
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
---
|
||||
title: '1004. Max Consecutive Ones III'
|
||||
description: Given a binary array nums and an integer k, return the maximum number of consecutive 1's in the array if you can flip at most k 0's
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
- { name: "Sliding Window", slug: "sliding-window" }
|
||||
- { name: "Prefix Sum", slug: "prefix-sum" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/56"
|
||||
sidebar:
|
||||
label: 'Max Consecutive Ones III'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2`
|
||||
- Output: `6`
|
||||
- Explanation: `[1,1,1,0,0,1,1,1,1,1,1]` Bolded numbers were flipped from `0` to `1`. The longest subarray is underlined.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], k = 3`
|
||||
- Output: `10`
|
||||
- Explanation: `[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]` Bolded numbers were flipped from `0` to `1`. The longest subarray is underlined.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^5`
|
||||
- `nums[i]` is either 0 or 1.
|
||||
- `0 <= k <= nums.length`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def longestOnes(self, nums: list[int], k: int) -> int:
|
||||
left = 0
|
||||
cur = 0
|
||||
ans = 0
|
||||
|
||||
for right in range(len(nums)):
|
||||
if nums[right] == 0:
|
||||
cur += 1
|
||||
while cur > k:
|
||||
if nums[left] == 0:
|
||||
cur -= 1
|
||||
left += 1
|
||||
|
||||
ans = max(ans, right - left + 1)
|
||||
|
||||
return ans
|
||||
```
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
---
|
||||
title: '121. Best Time to Buy and Sell Stock'
|
||||
description: You are given an array prices where prices[i] is the price of a given stock on the i^th day
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Dynamic Programming", slug: "dynamic-programming" }
|
||||
video: "1pkOgXD63yU"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/50"
|
||||
sidebar:
|
||||
label: 'Best Time to Buy and Sell Stock'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `prices = [7,1,5,3,6,4]`
|
||||
- Output: `5`
|
||||
- Explanation: Buy on day `2` (price = `1`) and sell on day `5` (price = `6`), profit = `6-1 = 5`. Note that buying on day `2` and selling on day `1` is not allowed because you must buy before you sell.
|
||||
|
||||
### Example 2:
|
||||
- Input: `prices = [7,6,4,3,1]`
|
||||
- Output: `0`
|
||||
- Explanation: In this case, no transactions are done and the max profit = `0`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= prices.length <= 10^5`
|
||||
- `0 <= prices[i] <= 10^4`
|
||||
|
||||
## Approach
|
||||
|
||||
::::warning
|
||||
The diagram traces the code below literally. That code does not run: `curr` and `ans` are never initialised, so the first `curr > left` test raises `NameError`, and `left` holds a price rather than an index, so `prices[left]` indexes by value.
|
||||
::::
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["maxProfit(prices)"]) --> I["left = min(prices)"]
|
||||
I --> F{"more right in range(len(prices))?"}
|
||||
F -- no --> E(["return ans"])
|
||||
F -- yes --> W{"curr > left?"}
|
||||
W -- yes --> P["curr -= prices[left]; left += 1"]
|
||||
P --> W
|
||||
W -- no --> M["ans = max(ans, curr)"]
|
||||
M --> F
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def maxProfit(self, prices: List[int]) -> int:
|
||||
left = min(prices)
|
||||
for right in range(len(prices)):
|
||||
while curr > left:
|
||||
curr -= prices[left]
|
||||
left += 1
|
||||
ans = max(ans, curr)
|
||||
return ans
|
||||
```
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
---
|
||||
title: '209. Minimum Size Subarray Sum'
|
||||
description: Given an array of positive integers nums and a positive integer target, return the minimal length of a subarray whose sum is greater than or equal to target. If there is no such subarray, return 0 instead
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
- { name: "Sliding Window", slug: "sliding-window" }
|
||||
- { name: "Prefix Sum", slug: "prefix-sum" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/54"
|
||||
sidebar:
|
||||
label: 'Minimum Size Subarray Sum'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log(n)).
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `target = 7, nums = [2,3,1,2,4,3]`
|
||||
- Output: `2`
|
||||
- Explanation: The subarray `[4,3]` has the minimal length under the problem constraint.
|
||||
|
||||
### Example 2:
|
||||
- Input: `target = 4, nums = [1,4,4]`
|
||||
- Output: `1`
|
||||
|
||||
### Example 3:
|
||||
- Input: `target = 11, nums = [1,1,1,1,1,1,1,1]`
|
||||
- Output: `0`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= target <= 10^9`
|
||||
- `1 <= nums.length <= 10^5`
|
||||
- `1 <= nums[i] <= 10^4`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def minSubArrayLen(self, target: int, nums: list[int]) -> int:
|
||||
window_sum = 0
|
||||
length = len(nums) + 1
|
||||
left = 0
|
||||
|
||||
for right in range(len(nums)):
|
||||
window_sum += nums[right]
|
||||
while window_sum >= target:
|
||||
length = min(length, right - left + 1)
|
||||
window_sum -= nums[left]
|
||||
left += 1
|
||||
if length > len(nums):
|
||||
return 0
|
||||
return length
|
||||
```
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
---
|
||||
title: '3. Longest Substring Without Repeating Characters'
|
||||
description: Given a string s, find the length of the longest substring without duplicate characters
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "String", slug: "string" }
|
||||
- { name: "Sliding Window", slug: "sliding-window" }
|
||||
video: "wiGpQwVHdE0"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/51"
|
||||
sidebar:
|
||||
label: 'Longest Substring Without Repeating Characters'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "abcabcbb"`
|
||||
- Output: `3`
|
||||
- Explanation: The answer is "abc", with the length of `3`. Note that "bca" and "cab" are also correct answers.
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "bbbbb"`
|
||||
- Output: `1`
|
||||
- Explanation: The answer is "b", with the length of `1`.
|
||||
|
||||
### Example 3:
|
||||
- Input: `s = "pwwkew"`
|
||||
- Output: `3`
|
||||
- Explanation: The answer is "wke", with the length of `3`. Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `0 <= s.length <= 10^5`
|
||||
- `s` consists of English letters, digits, symbols and spaces.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["lengthOfLongestSubstring(s)"]) --> I["left = 0, ans = 0, window = set()"]
|
||||
I --> L{"more (right, c) in s?"}
|
||||
L -- no --> E(["return ans"])
|
||||
L -- yes --> W{"c already in window?"}
|
||||
W -- yes --> P["window.remove(s[left]); left += 1 — shrink until c is free"]
|
||||
P --> W
|
||||
W -- no --> A["window.add(c)"]
|
||||
A --> M["ans = max(ans, right - left + 1)"]
|
||||
M --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def lengthOfLongestSubstring(self, s: str) -> int:
|
||||
left = 0
|
||||
ans = 0
|
||||
window = set()
|
||||
for right, c in enumerate(s):
|
||||
while c in window:
|
||||
window.remove(s[left])
|
||||
left += 1
|
||||
window.add(c)
|
||||
ans = max(ans, right - left + 1)
|
||||
|
||||
return ans
|
||||
```
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
---
|
||||
title: '424. Longest Repeating Character Replacement'
|
||||
description: 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
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "String", slug: "string" }
|
||||
- { name: "Sliding Window", slug: "sliding-window" }
|
||||
video: "gqXU1UyA8pk"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/52"
|
||||
sidebar:
|
||||
label: 'Longest Repeating Character Replacement'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### 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`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["characterReplacement(s, k)"]) --> I["count = {}, res = 0, l = 0, maxF = 0"]
|
||||
I --> L{"more (r, c) in s?"}
|
||||
L -- no --> E(["return res"])
|
||||
L -- yes --> A["count[c] += 1; maxF = max(maxF, count[c])"]
|
||||
A --> W{"(r - l + 1) - maxF > k? — too many chars to replace"}
|
||||
W -- yes --> P["count[s[l]] -= 1; l += 1 — shrink from the left"]
|
||||
P --> W
|
||||
W -- no --> M["res = max(res, r - l + 1)"]
|
||||
M --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def characterReplacement(self, s: str, k: int) -> int:
|
||||
count = {}
|
||||
res = 0
|
||||
|
||||
l = 0
|
||||
maxF = 0
|
||||
for r, c in enumerate(s):
|
||||
count[c] = 1 + count.get(c, 0)
|
||||
maxF = max(maxF, count[c])
|
||||
|
||||
while (r - l + 1) - maxF > k:
|
||||
count[s[l]] -= 1
|
||||
l += 1
|
||||
|
||||
res = max(res, r - l + 1)
|
||||
return res
|
||||
```
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
---
|
||||
title: '567. Permutation in String'
|
||||
description: Given two strings s1 and s2, return true if s2 contains a permutation of s1, or false otherwise
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Hash Table", slug: "hash-table" }
|
||||
- { name: "Two Pointers", slug: "two-pointers" }
|
||||
- { name: "String", slug: "string" }
|
||||
- { name: "Sliding Window", slug: "sliding-window" }
|
||||
video: "UbyhOgBN834"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/53"
|
||||
sidebar:
|
||||
label: 'Permutation in String'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `s1 = "ab", s2 = "eidbaooo"`
|
||||
- Output: `true`
|
||||
- Explanation: `s2` contains one permutation of `s1` ("ba").
|
||||
|
||||
### Example 2:
|
||||
- Input: `s1 = "ab", s2 = "eidboaoo"`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s1.length, s2.length <= 10^4`
|
||||
- `s1` and `s2` consist of lowercase English letters.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["checkInclusion(s1, s2)"]) --> G{"k = len(s1) > len(s2)?"}
|
||||
G -- yes --> X(["return False"])
|
||||
G -- no --> I["need = Counter(s1), window = Counter()"]
|
||||
I --> L{"more (right, c) in s2?"}
|
||||
L -- no --> E(["return False"])
|
||||
L -- yes --> A["window[c] += 1"]
|
||||
A --> B{"right >= k? — window is now longer than k"}
|
||||
B -- yes --> C["drop s2[right - k] from window, deleting the key at 0"]
|
||||
B -- no --> Q
|
||||
C --> Q{"window == need?"}
|
||||
Q -- yes --> R(["return True"])
|
||||
Q -- no --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
from collections import Counter
|
||||
|
||||
|
||||
class Solution:
|
||||
def checkInclusion(self, s1: str, s2: str) -> bool:
|
||||
k = len(s1)
|
||||
if k > len(s2):
|
||||
return False
|
||||
|
||||
need = Counter(s1)
|
||||
window = Counter()
|
||||
|
||||
for right, c in enumerate(s2):
|
||||
window[c] += 1
|
||||
if right >= k:
|
||||
left_char = s2[right - k]
|
||||
window[left_char] -= 1
|
||||
if window[left_char] == 0:
|
||||
del window[left_char]
|
||||
if window == need:
|
||||
return True
|
||||
|
||||
return False
|
||||
```
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
---
|
||||
title: '643. Maximum Average Subarray I'
|
||||
description: You are given an integer array nums consisting of n elements, and an integer k
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Sliding Window", slug: "sliding-window" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/55"
|
||||
sidebar:
|
||||
label: 'Maximum Average Subarray I'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,12,-5,-6,50,3], k = 4`
|
||||
- Output: `12.75000`
|
||||
- Explanation: Maximum average is `(12 - 5 - 6 + 50`) / `4 = 51 / 4 = 12.75`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [5], k = 1`
|
||||
- Output: `5.00000`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == nums.length`
|
||||
- `1 <= k <= n <= 10^5`
|
||||
- `-10^4 <= nums[i] <= 10^4`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def findMaxAverage(self, nums: list[int], k: int) -> float:
|
||||
window_sum = 0
|
||||
for i in range(k):
|
||||
window_sum += nums[i]
|
||||
largest = window_sum
|
||||
|
||||
for right in range(k, len(nums)):
|
||||
left = right - k
|
||||
window_sum -= nums[left]
|
||||
window_sum += nums[right]
|
||||
largest = max(largest, window_sum)
|
||||
|
||||
return largest / k
|
||||
```
|
||||
@@ -1,214 +0,0 @@
|
||||
---
|
||||
title: Sliding Window
|
||||
description: 'Sliding window is a specialized two-pointer family where the pointers define a contiguous interval and you maintain information about that entire interval as it moves.'
|
||||
hidden: true
|
||||
---
|
||||
|
||||
|
||||
<YouTube id="tSTO9w3piAo" title="Sliding Window" />
|
||||
|
||||
|
||||
Many problems have two moving boundaries. That alone does not make them sliding window problems.
|
||||
|
||||
A problem belongs to this family when:
|
||||
|
||||
- the answer depends on the subarray or substring between left and right
|
||||
- you can update the window state incrementally as elements enter or leave
|
||||
- you maintain a condition that tells you whether the window is valid
|
||||
|
||||
:::tip
|
||||
The rule for all three: every element enters once and leaves once, so the whole thing runs in O(n).
|
||||
:::
|
||||
|
||||
<Accordion>
|
||||
<AccordionItem title="What is an invariant?">
|
||||
An invariant is a statement that stays true before and after every iteration. In a sliding window, that statement usually describes the window itself, such as “the window is valid,” “it has no duplicates,” or “its sum is at most the target.” It can also describe a helper structure, such as “the frequency map matches the characters currently inside the window.”
|
||||
</AccordionItem>
|
||||
<AccordionItem title="Why invariants matter?">
|
||||
Without an invariant, shrinking the window is just a guess. You no longer know when the window is valid, when to update the answer, or why the left pointer should stop. The invariant is what makes the algorithm correct.
|
||||
</AccordionItem>
|
||||
<AccordionItem title="How sliding window differs from other two-pointer families?">
|
||||
Sliding window is not the same as every other two-pointer pattern. In Container With Most Water, the interval is only the remaining search space. In sliding window, the interval itself is the thing you care about. In Remove Duplicates, the left side is already the finished answer prefix. In sliding window, both pointers describe a live window that is still being checked.
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
||||
|
||||
## 1. Fixed-size windows
|
||||
|
||||
:::tip
|
||||
The window size never changes. The main task is updating the window state efficiently when one element enters and one leaves.
|
||||
:::
|
||||
|
||||
|
||||
<Frame caption="Sliding Window Fixed" hint="">
|
||||
|
||||

|
||||
|
||||
</Frame>
|
||||
|
||||
|
||||
```python
|
||||
def sliding_window_fixed(input, window_size):
|
||||
ans = window = input[0:window_size]
|
||||
for right in range(window_size, len(input)):
|
||||
left = right - window_size
|
||||
remove input[left] from window
|
||||
append input[right] to window
|
||||
ans = optimal(ans, window)
|
||||
return ans
|
||||
```
|
||||
|
||||
<Steps>
|
||||
<Step title="">
|
||||
Add `nums[right]` to the window.
|
||||
</Step>
|
||||
<Step title="">
|
||||
If the window has `k` elements, record the answer.
|
||||
</Step>
|
||||
<Step title="">
|
||||
Remove the leftmost element so the window stays at size `k`.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
|
||||
## 2. Flexible-size windows with a validity rule
|
||||
|
||||
:::tip
|
||||
Here the window expands until invalid, then shrinks until valid again.
|
||||
:::
|
||||
|
||||
<Frame caption="Sliding Window Flexible" hint="">
|
||||
|
||||

|
||||
|
||||
</Frame>
|
||||
|
||||
|
||||
<Tabs inline>
|
||||
<Tab title="Longest Window">
|
||||
|
||||
```python
|
||||
def sliding_window_flexible_longest(input):
|
||||
initialize window, ans
|
||||
left = 0
|
||||
for right in range(len(input)):
|
||||
append input[right] to window
|
||||
while invalid(window): # update left until window is valid again
|
||||
remove input[left] from window
|
||||
left += 1
|
||||
ans = max(ans, window) # window is guaranteed to be valid here
|
||||
return ans
|
||||
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="Shortest Window">
|
||||
|
||||
```python
|
||||
def sliding_window_flexible_shortest(input):
|
||||
initialize window, ans
|
||||
left = 0
|
||||
for right in range(len(input)):
|
||||
append input[right] to window
|
||||
while valid(window):
|
||||
ans = min(ans, window) # window is guaranteed to be valid here
|
||||
remove input[left] from window
|
||||
left += 1
|
||||
return ans
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Steps>
|
||||
<Step title="">
|
||||
Add `nums[right]` to the window.
|
||||
</Step>
|
||||
<Step title="">
|
||||
While the window is invalid, remove `nums[left]` and move `left` up.
|
||||
</Step>
|
||||
<Step title="">
|
||||
The window is now valid. Record its size.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
---
|
||||
|
||||
## 3. Frequency-tracking windows
|
||||
|
||||
:::tip
|
||||
The difficulty comes from keeping the bookkeeping correct as characters enter and leave.
|
||||
:::
|
||||
|
||||
|
||||
<Frame caption="Frequency-tracking windows" hint="">
|
||||
|
||||

|
||||
|
||||
</Frame>
|
||||
|
||||
```python
|
||||
from collections import defaultdict
|
||||
|
||||
def frequency_window(s):
|
||||
left = 0
|
||||
counts = defaultdict(int)
|
||||
best = 0
|
||||
|
||||
for right in range(len(s)):
|
||||
counts[s[right]] += 1 # character enters
|
||||
|
||||
while counts[s[right]] > 1: # rule: no repeats
|
||||
counts[s[left]] -= 1 # character leaves
|
||||
left += 1
|
||||
|
||||
best = max(best, right - left + 1)
|
||||
|
||||
return best
|
||||
```
|
||||
|
||||
<Steps>
|
||||
<Step title="">
|
||||
Add `s[right]` to the window.
|
||||
</Step>
|
||||
<Step title="">
|
||||
While the window has more than one character, remove `s[left]` and move `left` up.
|
||||
</Step>
|
||||
<Step title="">
|
||||
The window is now valid. Record its size.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
---
|
||||
|
||||
For anagram or "minimum window substring" problems, you also keep a target count. Track how many characters currently match the target with one integer (`matched`). Update it only when a count crosses the target value. This keeps each step `O(1)`.
|
||||
|
||||
```python
|
||||
def anagram_window(s, p):
|
||||
need = defaultdict(int)
|
||||
for c in p:
|
||||
need[c] += 1
|
||||
|
||||
counts = defaultdict(int)
|
||||
matched = 0 # how many chars have counts[c] == need[c]
|
||||
result = []
|
||||
k = len(p)
|
||||
|
||||
for right in range(len(s)):
|
||||
c = s[right]
|
||||
counts[c] += 1
|
||||
if counts[c] == need[c]:
|
||||
matched += 1
|
||||
|
||||
if right >= k: # window too big, remove left
|
||||
d = s[right - k]
|
||||
if counts[d] == need[d]:
|
||||
matched -= 1
|
||||
counts[d] -= 1
|
||||
|
||||
if matched == len(need):
|
||||
result.append(right - k + 1)
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Sliding Window", order: 4, icon: "app-window", display: "page" });
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
---
|
||||
title: '150. Evaluate Reverse Polish Notation'
|
||||
description: You are given an array of strings tokens that represents an arithmetic expression in a Reverse Polish Notation
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Math", slug: "math" }
|
||||
- { name: "Stack", slug: "stack" }
|
||||
video: "iu0082c4HDE"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/69"
|
||||
sidebar:
|
||||
label: 'Evaluate Reverse Polish Notation'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `tokens = ["2","1","+","3","*"]`
|
||||
- Output: `9`
|
||||
- Explanation: `((2 + 1`) * `3`) = `9`
|
||||
|
||||
### Example 2:
|
||||
- Input: `tokens = ["4","13","5","/","+"]`
|
||||
- Output: `6`
|
||||
- Explanation: `(4 + (13 / 5`)) = `6`
|
||||
|
||||
### Example 3:
|
||||
- Input: `tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]`
|
||||
- Output: `22`
|
||||
- Explanation: `((10 * (6 / ((9 + 3`) * `-11`))) + `17`) + `5 = ((10 * (6 / (12 * -11`))) + `17`) + `5 = ((10 * (6 / -132`)) + `17`) + `5 = ((10 * 0`) + `17`) + `5 = (0 + 17`) + `5 = 17 + 5 = 22`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= tokens.length <= 10^4`
|
||||
- `tokens[i]` is either an operator: "+", "-", "*", or "/", or an integer in the range [-200, 200].
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["evalRPN(tokens)"]) --> I["stack = [], operations = + - * /"]
|
||||
I --> L{"more token c?"}
|
||||
L -- no --> E(["return stack[0]"])
|
||||
L -- yes --> Q{"c is an operator?"}
|
||||
Q -- no --> N["stack.append(int(c))"]
|
||||
N --> L
|
||||
Q -- yes --> P["y = stack.pop(), x = stack.pop() — order matters"]
|
||||
P --> C["stack.append(operations[c](x, y))"]
|
||||
C --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def evalRPN(self, tokens: List[str]) -> int:
|
||||
stack = []
|
||||
operations = {
|
||||
"+": lambda x, y: int(x + y),
|
||||
"-": lambda x, y: int(x - y),
|
||||
"*": lambda x, y: int(x * y),
|
||||
"/": lambda x, y: int(x / y),
|
||||
}
|
||||
|
||||
for c in tokens:
|
||||
if c in operations:
|
||||
y = stack.pop()
|
||||
x = stack.pop()
|
||||
calc_func = operations[c]
|
||||
result = calc_func(x, y)
|
||||
stack.append(result)
|
||||
else:
|
||||
stack.append(int(c))
|
||||
|
||||
return stack[0]
|
||||
```
|
||||
@@ -1,82 +0,0 @@
|
||||
---
|
||||
title: '155. Min Stack'
|
||||
description: Design a stack that supports push, pop, top, and retrieving the minimum element in constant time
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Stack", slug: "stack" }
|
||||
- { name: "Design", slug: "design" }
|
||||
video: "qkLl7nAwDPo"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/68"
|
||||
sidebar:
|
||||
label: 'Min Stack'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
You must implement a solution with O(1) time complexity for each function.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: ``
|
||||
- Output: ``
|
||||
- Explanation: Input `["MinStack","push","push","push","getMin","pop","top","getMin"]` [[],[-2],[0],[-3],[],[],[],[]] Output `[null,null,null,null,-3,null,0,-2]` Explanation MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.getMin(); // return `-3` minStack.pop(); minStack.top(); // return `0` minStack.getMin(); // return `-2`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `-2^31 <= val <= 2^31 - 1`
|
||||
- Methods pop, top and getMin operations will always be called on non-empty stacks.
|
||||
- At most 3 * 10^4 calls will be made to push, pop, top, and getMin.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph state["two parallel stacks — same depth, always"]
|
||||
A["stack — the values"]
|
||||
B["minStack — the minimum as of that depth"]
|
||||
end
|
||||
state --> P
|
||||
subgraph P["push(value)"]
|
||||
P1["stack.append(value)"] --> P2["minStack.append(min(value, minStack[-1]))"]
|
||||
end
|
||||
state --> O
|
||||
subgraph O["pop()"]
|
||||
O1["pop both stacks together"]
|
||||
end
|
||||
state --> R
|
||||
subgraph R["top() / getMin() — O(1)"]
|
||||
R1(["stack[-1] / minStack[-1]"])
|
||||
end
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class MinStack:
|
||||
def __init__(self):
|
||||
self.stack = []
|
||||
self.minStack = []
|
||||
|
||||
def push(self, value: int) -> None:
|
||||
self.stack.append(value)
|
||||
value = min(value, self.minStack[-1] if self.minStack else value)
|
||||
self.minStack.append(value)
|
||||
|
||||
def pop(self) -> None:
|
||||
self.stack.pop()
|
||||
self.minStack.pop()
|
||||
|
||||
def top(self) -> int:
|
||||
return self.stack[-1]
|
||||
|
||||
def getMin(self) -> int:
|
||||
return self.minStack[-1]
|
||||
|
||||
|
||||
# Your MinStack object will be instantiated and called as such:
|
||||
# obj = MinStack()
|
||||
# obj.push(value)
|
||||
# obj.pop()
|
||||
# param_3 = obj.top()
|
||||
# param_4 = obj.getMin()
|
||||
```
|
||||
@@ -1,77 +0,0 @@
|
||||
---
|
||||
title: '20. Valid Parentheses'
|
||||
description: Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "String", slug: "string" }
|
||||
- { name: "Stack", slug: "stack" }
|
||||
- { name: "Bracket Sequences", slug: "bracket-sequences" }
|
||||
video: "WTzjTskDFMg"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/67"
|
||||
sidebar:
|
||||
label: 'Valid Parentheses'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "()"`
|
||||
- Output: `true`
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "()[]{}"`
|
||||
- Output: `true`
|
||||
|
||||
### Example 3:
|
||||
- Input: `s = "(]"`
|
||||
- Output: `false`
|
||||
|
||||
### Example 4:
|
||||
- Input: `s = "([])"`
|
||||
- Output: `true`
|
||||
|
||||
### Example 5:
|
||||
- Input: `s = "([)]"`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 10^4`
|
||||
- `s` consists of parentheses only '()[]{}'.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["isValid(s)"]) --> I["stack = [], pairs = closer to opener"]
|
||||
I --> L{"more char c?"}
|
||||
L -- no --> Z{"stack empty?"}
|
||||
Z -- yes --> T(["return True"])
|
||||
Z -- no --> U(["return False — unclosed openers left"])
|
||||
L -- yes --> Q{"c is a closer?"}
|
||||
Q -- no --> A["stack.append(c) — it is an opener"]
|
||||
A --> L
|
||||
Q -- yes --> M{"stack non-empty and pairs[c] == stack[-1]?"}
|
||||
M -- yes --> P["stack.pop() — matched"]
|
||||
P --> L
|
||||
M -- no --> F(["return False — mismatch"])
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def isValid(self, s: str) -> bool:
|
||||
stack = []
|
||||
pairs = {")": "(", "]": "[", "}": "{"}
|
||||
|
||||
for c in s:
|
||||
if c in pairs:
|
||||
if stack and pairs[c] == stack[-1]:
|
||||
stack.pop()
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
stack.append(c)
|
||||
|
||||
return True if not stack else False
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Stack
|
||||
description: 'Items are added and removed from one end, so the last item added is the first item removed.'
|
||||
hidden: true
|
||||
---
|
||||
@@ -1,3 +0,0 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Stack", order: 6, icon: "layers", display: "page" });
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
---
|
||||
title: '11. Container With Most Water'
|
||||
description: You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the i^th line are (i, 0) and (i, height[i])
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Two Pointers", slug: "two-pointers" }
|
||||
- { name: "Greedy", slug: "greedy" }
|
||||
video: "UuiTKBwPgAo"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/44"
|
||||
sidebar:
|
||||
label: 'Container With Most Water'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
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`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["maxArea(height)"]) --> I["res = 0, left = 0, right = len - 1"]
|
||||
I --> W{"left < right?"}
|
||||
W -- no --> E(["return res"])
|
||||
W -- yes --> A["area = (right - left) * min(height[left], height[right])"]
|
||||
A --> M["res = max(res, area)"]
|
||||
M --> C{"height[left] < height[right]?"}
|
||||
C -- yes --> L["left += 1 — drop the shorter wall"]
|
||||
C -- no --> R["right -= 1 — drop the shorter wall"]
|
||||
L --> W
|
||||
R --> W
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def maxArea(self, height: List[int]) -> int: # noqa: F821
|
||||
res = 0
|
||||
left = 0
|
||||
right = len(height) - 1
|
||||
|
||||
while left < right:
|
||||
area = (right - left) * min(height[left], height[right])
|
||||
res = max(res, area)
|
||||
if height[left] < height[right]:
|
||||
left += 1
|
||||
else:
|
||||
right -= 1
|
||||
|
||||
return res
|
||||
```
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
---
|
||||
title: '125. Valid Palindrome'
|
||||
description: A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Two Pointers", slug: "two-pointers" }
|
||||
- { name: "String", slug: "string" }
|
||||
video: "jJXJ16kPFWg"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/41"
|
||||
sidebar:
|
||||
label: 'Valid Palindrome'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "A man, a plan, a canal: Panama"`
|
||||
- Output: `true`
|
||||
- Explanation: `"amanaplanacanalpanama"` is a palindrome.
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "race a car"`
|
||||
- Output: `false`
|
||||
- Explanation: `"raceacar"` is not a palindrome.
|
||||
|
||||
### Example 3:
|
||||
- Input: `s = " "`
|
||||
- Output: `true`
|
||||
- Explanation: `s` is an empty string `""` after removing non-alphanumeric characters. Since an empty string reads the same forward and backward, it is a palindrome.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 2 * 10^5`
|
||||
- `s` consists only of printable ASCII characters.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["isPalindrome(s)"]) --> N["normal = s stripped of non-alphanumerics, lowercased"]
|
||||
N --> I["i = 0, j = normal.length - 1"]
|
||||
I --> W{"i < j?"}
|
||||
W -- no --> E(["return true — the pointers met in the middle"])
|
||||
W -- yes --> Q{"normal[i] != normal[j]?"}
|
||||
Q -- yes --> F(["return false"])
|
||||
Q -- no --> A["i++; j-- — step both inward"]
|
||||
A --> W
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string} s
|
||||
* @return {boolean}
|
||||
*/
|
||||
var isPalindrome = function(s) {
|
||||
let normal = s.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()
|
||||
let i = 0, j = normal.length - 1;
|
||||
|
||||
while (i < j) {
|
||||
if(normal[i] !== normal[j]) {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
j--;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
```
|
||||
@@ -1,105 +0,0 @@
|
||||
---
|
||||
title: '15. 3Sum'
|
||||
description: 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
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Two Pointers", slug: "two-pointers" }
|
||||
- { name: "Sorting", slug: "sorting" }
|
||||
video: "jzZsG8n2R9A"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/43"
|
||||
sidebar:
|
||||
label: '3Sum'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
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`
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["threeSum(nums)"]) --> O["nums.sort() — duplicates become adjacent"]
|
||||
O --> F{"more i in 0..n-1?"}
|
||||
F -- no --> E(["return result"])
|
||||
F -- yes --> D{"nums[i] == nums[i-1]?"}
|
||||
D -- yes --> F
|
||||
D -- no --> P["left = i+1, right = n-1, target = -nums[i]"]
|
||||
P --> W{"left < right?"}
|
||||
W -- no --> F
|
||||
W -- yes --> C["current = nums[left] + nums[right]"]
|
||||
C --> Q{"current vs target"}
|
||||
Q -- equal --> A["append triplet, skip equal neighbours, left += 1, right -= 1"]
|
||||
A --> W
|
||||
Q -- "current < target" --> L["left += 1 — need a bigger sum"]
|
||||
L --> W
|
||||
Q -- "current > target" --> R["right -= 1 — need a smaller sum"]
|
||||
R --> W
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def threeSum(self, nums: list[int]) -> list[list[int]]:
|
||||
nums.sort()
|
||||
result = []
|
||||
n = len(nums)
|
||||
|
||||
for i in range(n):
|
||||
# skip all zero
|
||||
if i > 0 and nums[i] == nums[i - 1]:
|
||||
continue
|
||||
|
||||
# two pointers
|
||||
left = i + 1
|
||||
right = n - 1
|
||||
target = -nums[i]
|
||||
|
||||
while left < right:
|
||||
current = nums[left] + nums[right]
|
||||
|
||||
if current == target:
|
||||
result.append([nums[i], nums[left], nums[right]])
|
||||
|
||||
# skip duplicates
|
||||
while left < right and nums[left] == nums[left + 1]:
|
||||
left += 1
|
||||
while left < right and nums[right] == nums[right - 1]:
|
||||
right -= 1
|
||||
|
||||
# shift pointers
|
||||
left += 1
|
||||
right -= 1
|
||||
|
||||
# since sorted, if current < target, then move left
|
||||
elif current < target:
|
||||
left += 1
|
||||
# since sorted, if current > target, then move right
|
||||
else:
|
||||
right -= 1
|
||||
|
||||
return result
|
||||
```
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
---
|
||||
title: '167. Two Sum II - Input Array Is Sorted'
|
||||
description: Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Let these two numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 <= numbers.length
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Two Pointers", slug: "two-pointers" }
|
||||
- { name: "Binary Search", slug: "binary-search" }
|
||||
video: "cQ1Oz4ckceM"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/42"
|
||||
sidebar:
|
||||
label: 'Two Sum II - Input Array Is Sorted'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
::::warning
|
||||
Your solution must use only constant extra space.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `numbers = [2,7,11,15], target = 9`
|
||||
- Output: `[1,2]`
|
||||
- Explanation: The sum of `2` and `7` is `9`. Therefore, `index1 = 1`, `index2 = 2`. We return `[1, 2]`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `numbers = [2,3,4], target = 6`
|
||||
- Output: `[1,3]`
|
||||
- Explanation: The sum of `2` and `4` is `6`. Therefore `index1 = 1`, `index2 = 3`. We return `[1, 3]`.
|
||||
|
||||
### Example 3:
|
||||
- Input: `numbers = [-1,0], target = -1`
|
||||
- Output: `[1,2]`
|
||||
- Explanation: The sum of `-1` and `0` is `-1`. Therefore `index1 = 1`, `index2 = 2`. We return `[1, 2]`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `2 <= numbers.length <= 3 * 10^4`
|
||||
- `-1000 <= numbers[i] <= 1000`
|
||||
- `numbers` is sorted in non-decreasing order.
|
||||
- `-1000 <= target <= 1000`
|
||||
- The tests are generated such that there is exactly one solution.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["twoSum(numbers, target)"]) --> I["i = 0, j = len - 1"]
|
||||
I --> W{"i < j?"}
|
||||
W -- no --> E(["return []"])
|
||||
W -- yes --> C["c = numbers[i] + numbers[j]"]
|
||||
C --> Q{"c vs target"}
|
||||
Q -- equal --> R(["return [i+1, j+1] — 1-indexed"])
|
||||
Q -- "c < target" --> L["i += 1 — grow the sum"]
|
||||
L --> W
|
||||
Q -- "c > target" --> H["j -= 1 — shrink the sum"]
|
||||
H --> W
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def twoSum(self, numbers: List[int], target: int) -> List[int]:
|
||||
i = 0
|
||||
j = len(numbers) - 1
|
||||
|
||||
while i < j:
|
||||
c = numbers[i] + numbers[j]
|
||||
if c == target:
|
||||
return [i + 1, j + 1]
|
||||
elif c < target:
|
||||
i+=1
|
||||
else:
|
||||
j-=1
|
||||
return []
|
||||
```
|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
title: '189. Rotate Array'
|
||||
description: Given an integer array nums, rotate the array to the right by k steps, where k is non-negative
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Math", slug: "math" }
|
||||
- { name: "Two Pointers", slug: "two-pointers" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/47"
|
||||
sidebar:
|
||||
label: 'Rotate Array'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- 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]`
|
||||
|
||||
### Example 2:
|
||||
- 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]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^5`
|
||||
- `-2^31 <= nums[i] <= 2^31 - 1`
|
||||
- `0 <= k <= 10^5`
|
||||
- Try to come up with as many solutions as you can. There are at least three different ways to solve this problem.
|
||||
- Could you do it in-place with O(1) extra space?
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def rotate(self, nums: list[int], k: int) -> None:
|
||||
N = len(nums) - 1
|
||||
cut = k % len(nums)
|
||||
|
||||
def reverse(l, r):
|
||||
while l <= r:
|
||||
nums[l], nums[r] = nums[r], nums[l]
|
||||
l += 1
|
||||
r -= 1
|
||||
|
||||
reverse(0, N)
|
||||
reverse(0, cut - 1)
|
||||
reverse(cut, N)
|
||||
```
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
---
|
||||
title: '344. Reverse String'
|
||||
description: Write a function that reverses a string. The input string is given as an array of characters s
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Two Pointers", slug: "two-pointers" }
|
||||
- { name: "String", slug: "string" }
|
||||
video: "_d0T_2Lk2qA"
|
||||
sidebar:
|
||||
label: 'Reverse String'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
:::warning
|
||||
You must do this by modifying the input array in-place with O(1) extra memory.
|
||||
:::
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = ["h","e","l","l","o"]`
|
||||
- Output: `["o","l","l","e","h"]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = ["H","a","n","n","a","h"]`
|
||||
- Output: `["h","a","n","n","a","H"]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 10^5`
|
||||
- `s[i]` is a printable ascii character.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["reverseString(s)"]) --> I["i = 0, j = s.length - 1"]
|
||||
I --> W{"i < j?"}
|
||||
W -- no --> E(["done — s was reversed in place, nothing returned"])
|
||||
W -- yes --> A["swap s[i] and s[j]"]
|
||||
A --> B["i++; j--"]
|
||||
B --> W
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {character[]} s
|
||||
* @return {void} Do not return anything, modify s in-place instead.
|
||||
*/
|
||||
var reverseString = function(s) {
|
||||
let i = 0;
|
||||
let j = s.length - 1;
|
||||
|
||||
while (i < j) {
|
||||
[s[i], s[j]] = [s[j], s[i]];
|
||||
j--;
|
||||
i++;
|
||||
}
|
||||
};
|
||||
```
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
---
|
||||
title: '392. Is Subsequence'
|
||||
description: Given two strings s and t, return true if s is a subsequence of t, or false otherwise
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Two Pointers", slug: "two-pointers" }
|
||||
- { name: "String", slug: "string" }
|
||||
- { name: "Dynamic Programming", slug: "dynamic-programming" }
|
||||
video: "99RVfqklbCE"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/45"
|
||||
sidebar:
|
||||
label: 'Is Subsequence'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
::::warning
|
||||
Suppose there are lots of incoming s, say s1, s2, ..., sk where k >= 10^9, and you want to check one by one to see if t has its subsequence. In this scenario, how would you change your code?
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "abc", t = "ahbgdc"`
|
||||
- Output: `true`
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "axc", t = "ahbgdc"`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `0 <= s.length <= 100`
|
||||
- `0 <= t.length <= 10^4`
|
||||
- `s` and `t` consist only of lowercase English letters.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["isSubsequence(s, t)"]) --> G{"len(s) > len(t)?"}
|
||||
G -- yes --> X(["return False"])
|
||||
G -- no --> I["i = 0 into s, j = 0 into t"]
|
||||
I --> W{"i < len(s) and j < len(t)?"}
|
||||
W -- no --> E(["return i == len(s) — every char of s was matched"])
|
||||
W -- yes --> Q{"s[i] == t[j]?"}
|
||||
Q -- yes --> A["i += 1 — consume the match"]
|
||||
Q -- no --> B["j += 1 — always advance t"]
|
||||
A --> B
|
||||
B --> W
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def isSubsequence(self, s: str, t: str) -> bool:
|
||||
if len(s) > len(t):
|
||||
return False
|
||||
|
||||
i, j = 0, 0
|
||||
while i < len(s) and j < len(t):
|
||||
if s[i] == t[j]:
|
||||
i += 1
|
||||
j += 1
|
||||
|
||||
return i == len(s)
|
||||
```
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
---
|
||||
title: '42. Trapping Rain Water'
|
||||
description: Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Two Pointers", slug: "two-pointers" }
|
||||
- { name: "Dynamic Programming", slug: "dynamic-programming" }
|
||||
- { name: "Stack", slug: "stack" }
|
||||
- { name: "Monotonic Stack", slug: "monotonic-stack" }
|
||||
issue: "https://github.com/prdlk/leetcode/issues/211"
|
||||
sidebar:
|
||||
label: 'Trapping Rain Water'
|
||||
badge: 'Hard'
|
||||
---
|
||||
|
||||
### Example 1:
|
||||
- Input: `height = [0,1,0,2,1,0,1,3,2,1,2,1]`
|
||||
- Output: `6`
|
||||
- Explanation: The above elevation map (black section) is represented by array `[0,1,0,2,1,0,1,3,2,1,2,1]`. In this case, `6` units of rain water (blue section) are being trapped.
|
||||
|
||||
### Example 2:
|
||||
- Input: `height = [4,2,0,3,2,5]`
|
||||
- Output: `9`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == height.length`
|
||||
- `1 <= n <= 2 * 10^4`
|
||||
- `0 <= height[i] <= 10^5`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def trap(self, height: list[int]) -> int:
|
||||
left, right = 0, len(height) - 1
|
||||
leftMax, rightMax = 0, 0
|
||||
total = 0
|
||||
|
||||
while left < right:
|
||||
leftMax = max(leftMax, height[left])
|
||||
rightMax = max(rightMax, height[right])
|
||||
|
||||
if height[left] < height[right]:
|
||||
total += leftMax - height[left]
|
||||
left += 1
|
||||
else:
|
||||
total += rightMax - height[right]
|
||||
right -= 1
|
||||
|
||||
return total
|
||||
```
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
---
|
||||
title: '977. Squares of a Sorted Array'
|
||||
description: Given an integer array nums sorted in non-decreasing order, return an array of the squares of each number sorted in non-decreasing order
|
||||
icon: dot
|
||||
topics:
|
||||
- { name: "Array", slug: "array" }
|
||||
- { name: "Two Pointers", slug: "two-pointers" }
|
||||
- { name: "Sorting", slug: "sorting" }
|
||||
video: "FPCZsG_AkUg"
|
||||
issue: "https://github.com/prdlk/leetcode/issues/46"
|
||||
sidebar:
|
||||
label: 'Squares of a Sorted Array'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
::::warning
|
||||
Squaring each element and sorting the new array is very trivial, could you find an O(n) solution using a different approach?
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [-4,-1,0,3,10]`
|
||||
- Output: `[0,1,9,16,100]`
|
||||
- Explanation: After squaring, the array becomes `[16,1,0,9,100]`. After sorting, it becomes `[0,1,9,16,100]`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [-7,-3,2,3,11]`
|
||||
- Output: `[4,9,9,49,121]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^4`
|
||||
- `-10^4 <= nums[i] <= 10^4`
|
||||
- `nums` is sorted in non-decreasing order.
|
||||
|
||||
## Approach
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["sortedSquares(nums)"]) --> I["ans = Array(n), left = 0, right = n - 1"]
|
||||
I --> L{"more i from n-1 down to 0?"}
|
||||
L -- no --> E(["return ans"])
|
||||
L -- yes --> C{"abs(nums[left]) < abs(nums[right])?"}
|
||||
C -- yes --> R["square = nums[right]; right--"]
|
||||
C -- no --> F["square = nums[left]; left++"]
|
||||
R --> W["ans[i] = square * square — fill from the back, largest first"]
|
||||
F --> W
|
||||
W --> L
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @return {number[]}
|
||||
*/
|
||||
var sortedSquares = function(nums) {
|
||||
let n = nums.length;
|
||||
let ans = new Array(nums.length);
|
||||
let left = 0, right = nums.length - 1;
|
||||
|
||||
for (let i = n -1; i >= 0; i--){
|
||||
let square;
|
||||
if(Math.abs(nums[left]) < Math.abs(nums[right])){
|
||||
square = nums[right];
|
||||
right--;
|
||||
}else{
|
||||
square = nums[left];
|
||||
left++;
|
||||
}
|
||||
ans[i] = square*square;
|
||||
}
|
||||
return ans;
|
||||
};
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Two Pointers
|
||||
description: 'Two indices move through the data from different positions and meet at the answer.'
|
||||
hidden: true
|
||||
---
|
||||
@@ -1,3 +0,0 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Two Pointers", order: 3, icon: "arrow-left-right", display: "page" });
|
||||
Reference in new issue
Block a user