文章目录
- 二分法
-
- 旋转数组
-
- 33. 搜索旋转排序数组 [旋转数组] [目标值] (二分法)
- 元素边界
-
- 34. 在排序数组中查找元素的第一个和最后一个位置 [有序数组] > [元素边界] > (二分法)
- 81. 搜索旋转排序数组Ⅱ [旋转数组] [有重] [目标值] (二分法)
- 153. 寻找旋转排序数组中的最小值 [旋转数组] [最小值] (二分法)
- 双指针
-
- 元素合并
-
- 21. 合并两个有序链表 [有序链表] [合并] (双指针) (归并)
- 元素交换
-
- LCR 139. 训练计划 I [数组] [元素交换] (双指针)
- 元素相交
-
- 142. 环形链表II [链表] > [环] > (双指针)
- 160. 相交链表 [链表] > [相交] > (双指针)
- 面积
-
- 11. 盛最多水的容器 [数组] [面积] (双指针)
- 42. 接雨水 [数组] [面积] (双指针)
- 其他
-
- 31. 下一个排列 [数组] [排列] (双指针) (推导)
- 三指针
-
- 链表反转
-
- 25. K 个一组翻转链表 [链表] [分组反转] (三指针)
- 92. 反转链表II [链表] [反转] (三指针)
- 206. 反转链表 [链表] [反转] (三指针)
- 快速排序
-
- 215. 数组中的第K个最大元素 [数组] [第K大元素] (三指针) (快速排序)
- 912. 排序数组 [数组] [排序] (三指针) (快速排序)
- 滑动窗口
-
- 子串
-
- 3. 无重复字符的最长子串 [字符串] [子串] (滑动窗口)
- 区间和
-
- 1423. 可获得的最大点数 [数组] > [区间外最大值] > [区间内最小值] > (定长滑动窗口)
二分法
旋转数组
33. 搜索旋转排序数组 [旋转数组] [目标值] (二分法)
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
if (nums[mid] <= nums[0]) {
if (nums[mid] < target && target <= nums[n - 1]) {
left = mid + 1;
} else {
right = mid - 1;
}
} else {
if (nums[0] <= target && target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
return -1;
}
};
元素边界
34. 在排序数组中查找元素的第一个和最后一个位置 [有序数组] > [元素边界] > (二分法)
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left = find_l(nums, target);
int right = find_r(nums,target);
return {left, right};
}
int find_l(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] >= target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
if (0 <= left && left < n && nums[left] == target) {
return left;
}
return -1;
}
int find_r(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
if (0 <= right && right < n && nums[right] == target) {
return right;
}
return -1;
}
};
81. 搜索旋转排序数组Ⅱ [旋转数组] [有重] [目标值] (二分法)
class Solution {
public:
bool search(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return true;
if (nums[mid] == nums[left]) {
left++;
continue;
}
if (nums[mid] == nums[right]) {
right--;
continue;
}
if (nums[mid] < nums[0]) {
if (nums[mid] < target && target <= nums[n - 1]) {
left = mid + 1;
} else {
right = mid - 1;
}
} else {
if (nums[0] <= target && target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
return false;
}
};
153. 寻找旋转排序数组中的最小值 [旋转数组] [最小值] (二分法)
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < nums[right]) {
right = mid;
} else if (nums[mid] > nums[right]) {
left = mid + 1;
} else {
right--;
}
}
return nums[left];
}
};
双指针
元素合并
21. 合并两个有序链表 [有序链表] [合并] (双指针) (归并)
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* dummy = new ListNode(-1), * cur = dummy;
ListNode* p1 = list1, * p2 = list2;
while (p1 != nullptr && p2 != nullptr) {
if (p1->val < p2->val) {
cur->next = p1;
p1 = p1->next;
} else {
cur->next = p2;
p2 = p2->next;
}
cur = cur->next;
}
if (p1 != nullptr) cur->next = p1;
if (p2 != nullptr) cur->next = p2;
return dummy->next;
}
};
元素交换
LCR 139. 训练计划 I [数组] [元素交换] (双指针)
class Solution {
public:
vector<int> trainingPlan(vector<int>& actions) {
int n = actions.size();
if (n <= 1) return actions;
int left = 0, right = n - 1;
while (left < right) {
while (left < right && actions[left] % 2 == 1) {
left++;
}
while (left < right && actions[right] % 2 == 0) {
right--;
}
std::swap(actions[left], actions[right]);
}
return actions;
}
};
元素相交
142. 环形链表II [链表] > [环] > (双指针)
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* dummy = new ListNode(-1);
dummy->next = head;
ListNode* fast = dummy, * slow = dummy;
while (fast->next && fast->next->next) {
slow = slow->next;
fast = fast->next->next;
if (fast == slow) {
fast = dummy;
while (fast != slow) {
slow = slow->next;
fast = fast->next;
}
return fast;
}
}
return nullptr;
}
};
160. 相交链表 [链表] > [相交] > (双指针)
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p1 = headA, *p2 = headB;
while (p1 != p2) {
if (p1 == nullptr) p1 = headB;
else p1 = p1->next;
if (p2 == nullptr) p2 = headA;
else p2 = p2->next;
}
return p1;
}
};
面积
11. 盛最多水的容器 [数组] [面积] (双指针)
class Solution {
public:
int maxArea(vector<int>& height) {
int left = 0, right = height.size() - 1;
int res = 0, cur = 0;
while (left < right) {
cur = min(height[left], height[right]) * (right - left);
res = max(res, cur);
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return res;
}
};
42. 接雨水 [数组] [面积] (双指针)
class Solution {
public:
int trap(vector<int>& height) {
int left = 0, right = height.size() - 1;
int left_max = height[left], right_max = height[right];
int cur = 0, res = 0;
while (left <= right) {
left_max = max(left_max, height[left]);
right_max = max(right_max, height[right]);
if (left_max < right_max) {
res += left_max - height[left];
left++;
} else {
res += right_max - height[right];
right--;
}
}
return res;
}
};
其他
31. 下一个排列 [数组] [排列] (双指针) (推导)
class Solution {
private:
int flag = 0;
public:
void nextPermutation(vector<int>& nums) {
int n = nums.size();
int i = n - 2, j = n - 1;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i >= 0) {
while (j > i && nums[j] <= nums[i]) {
j--;
}
swap(nums[i], nums[j]);
reverse(nums.begin() + i + 1, nums.end());
} else {
reverse(nums.begin(), nums.end());
}
return;
}
};
三指针
链表反转
25. K 个一组翻转链表 [链表] [分组反转] (三指针)
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummy = new ListNode(-1);
dummy->next = head;
ListNode* pre = dummy, * end = dummy;
while (end->next != nullptr) {
for (int i = 0; i < k && end != nullptr; ++i) {
end = end->next;
}
if (end == nullptr) break;
ListNode* start = pre->next, * next = end->next;
end->next = nullptr;
pre->next = reverse(start);
start->next = next;
pre = start;
end = start;
}
return dummy->next;
}
ListNode* reverse(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
while (cur != nullptr) {
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
92. 反转链表II [链表] [反转] (三指针)
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode* dummy = new ListNode(-1);
dummy->next = head;
ListNode* pre = dummy, * end = dummy;
for (int i = 0; i < left - 1; ++i) pre = pre->next;
cout << pre->val;
for (int j = 0; j < right; ++j) end = end->next;
ListNode* start = pre->next, * next = end->next;
end->next = nullptr;
pre->next = reverse(start);
start->next = next;
return dummy->next;
}
ListNode* reverse(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
while (cur != nullptr) {
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
206. 反转链表 [链表] [反转] (三指针)
class Solution {
public:
ListNode* reverseList(ListNode* head) {
return reverse(head);
}
ListNode* reverse(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
while (cur != nullptr) {
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
快速排序
215. 数组中的第K个最大元素 [数组] [第K大元素] (三指针) (快速排序)
class Solution {
private:
int target;
int res;
public:
int findKthLargest(vector<int>& nums, int k) {
int n = nums.size();
target = n - k;
quickSort(nums, 0, n - 1);
return res;
}
void quickSort(vector<int>& nums, int left, int right) {
if (left > right) return;
if (left == right && left == target) {
res = nums[target];
return;
}
vector<int> edge = part(nums, left, right);
if (edge[0] <= target && target <= edge[1]) {
res = nums[target];
return;
}
quickSort(nums, left, edge[0] - 1);
quickSort(nums, edge[1] + 1, right);
}
vector<int> part(vector<int>& nums, int left, int right) {
int pivot_idx = rand() % (right - left + 1) + left;
int pivot = nums[pivot_idx];
swap(nums[pivot_idx], nums[left]);
int curp = left + 1, leftp = left, rightp = right + 1;
while (curp < rightp) {
if (nums[curp] < pivot) {
leftp++;
swap(nums[curp], nums[leftp]);
curp++;
} else if (nums[curp] > pivot) {
rightp--;
swap(nums[curp], nums[rightp]);
} else {
curp++;
}
}
swap(nums[left], nums[leftp]);
return {leftp, rightp - 1};
}
};
912. 排序数组 [数组] [排序] (三指针) (快速排序)
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int n = nums.size();
quickSort(nums, 0, n - 1);
return nums;
}
void quickSort(vector<int>& nums, int left, int right) {
if (left > right) return;
vector<int> edge = part(nums, left, right);
quickSort(nums, left, edge[0] - 1);
quickSort(nums, edge[1] + 1, right);
}
vector<int> part(vector<int>& nums, int left, int right) {
int pivot_idx = rand() % (right - left + 1) + left;
int pivot = nums[pivot_idx];
swap(nums[pivot_idx], nums[left]);
int curp = left + 1, leftp = left, rightp = right + 1;
while (curp < rightp) {
if (nums[curp] < pivot) {
leftp++;
swap(nums[curp], nums[leftp]);
curp++;
} else if (nums[curp] > pivot) {
rightp--;
swap(nums[curp], nums[rightp]);
} else {
curp++;
}
}
swap(nums[left], nums[leftp]);
return {leftp, rightp - 1};
}
};
滑动窗口
子串
3. 无重复字符的最长子串 [字符串] [子串] (滑动窗口)
class Solution {
private:
unordered_map<char, int> umap;
int res = 0;
public:
int lengthOfLongestSubstring(string s) {
int n = s.size();
int left = 0, right = 0;
while (right < n) {
char cur_r = s[right++];
umap[cur_r]++;
while (umap[cur_r] > 1) {
char cur_l = s[left++];
umap[cur_l]--;
}
res = max(res, right - left);
}
return res;
}
};
区间和
1423. 可获得的最大点数 [数组] > [区间外最大值] > [区间内最小值] > (定长滑动窗口)
class Solution {
public:
int maxScore(vector<int>& cardPoints, int k) {
int n = cardPoints.size();
int windowSize = n - k;
int sum = accumulate(cardPoints.begin(), cardPoints.begin() + windowSize, 0);
int min_val = sum;
for (int i = 0; i < n - windowSize; ++i) {
int left = i, right = i + windowSize;
sum += cardPoints[right] - cardPoints[left];
min_val = min(min_val, sum);
}
return accumulate(cardPoints.begin(), cardPoints.end(), 0) - min_val;
}
};