位运算直接操作二进制位,效率极高,常用于实现哈希、状态压缩和整数的特殊计算。
核心思想:
^
: 核心性质是 a ^ a = 0
和 a ^ 0 = a
。这个“消消乐”的特性在寻找只出现一次或两次的数字时非常有效。&
: 常用于检查某一位是否为1。例如,x & 1
可以判断 x
的最低位。int
(32位) 可以表示32个不同元素的存在状态,极大地节省了空间。经典应用场景:
[0, n]
的完整序列和残缺数组的所有数字进行异或操作,最终结果即为缺失的数字。
a ^ b
计算无进位和,
(a & b) << 1
计算进位,循环直至进位为0。
不使用 +
和 -
运算符,计算两个整数 a
和 b
的和。
C++
#include
class Solution {
public:
int getSum(int a, int b) {
// 当进位为0时,循环终止
while (b != 0) {
// 无符号整型用于处理负数左移时可能产生的未定义行为
unsigned int carry = (unsigned int)(a & b) << 1;
// 计算无进位和
a = a ^ b;
// 更新进位
b = carry;
}
return a;
}
};
// int main() {
// Solution sol;
// std::cout << sol.getSum(2, 3) << std::endl; // 输出: 5
// return 0;
// }
模拟题要求根据题意,将现实或抽象的过程用代码实现。这类问题通常不涉及复杂的算法,但对代码的实现能力和细节处理要求很高。
核心思想: 准确理解题目描述的每一个规则和约束,将过程分解为清晰的步骤,并用代码逻辑一一对应。
关键点
:
状态变量: 使用合适的变量来跟踪过程中的状态变化(例如,行号、方向、计数器等)。
将一个字符串 s
按给定的行数 numRows
进行 Z 字形排列,然后按行读取输出。
C++
#include
#include
#include
class Solution {
public:
std::string convert(std::string s, int numRows) {
if (numRows == 1) return s;
std::vector rows(std::min((int)s.length(), numRows));
int currentRow = 0;
bool goingDown = false;
for (char c : s) {
rows[currentRow] += c;
if (currentRow == 0 || currentRow == numRows - 1) {
goingDown = !goingDown;
}
currentRow += goingDown ? 1 : -1;
}
std::string result;
for (const std::string& row : rows) {
result += row;
}
return result;
}
};
// int main() {
// Solution sol;
// std::cout << sol.convert("PAYPALISHIRING", 3) << std::endl; // 输出: "PAHNAPLSIIGYIR"
// return 0;
// }
分治是一种将大问题分解为若干个规模更小但结构相同的子问题,递归地解决这些子问题,然后将子问题的解合并以得到原问题的解的策略。快速排序和归并排序是其经典应用。
核心思想 (三路快排)
:
优点: 平均时间复杂度为 O(NlogN),通常是实际应用中最快的内排序算法。
应用
:
C++
#include
#include
#include
#include
class Solution {
private:
// 荷兰国旗问题(三路快排)的分割操作
void qsort(std::vector& nums, int l, int r) {
if (l >= r) return;
// 随机选择基准,避免最坏情况
int pivot = nums[l + rand() % (r - l + 1)];
int i = l, lt = l - 1, gt = r + 1;
while (i < gt) {
if (nums[i] < pivot) {
std::swap(nums[++lt], nums[i++]);
} else if (nums[i] > pivot) {
std::swap(nums[--gt], nums[i]);
} else {
i++;
}
}
qsort(nums, l, lt);
qsort(nums, gt, r);
}
public:
std::vector sortArray(std::vector& nums) {
srand(time(NULL));
qsort(nums, 0, nums.size() - 1);
return nums;
}
};
// int main() {
// Solution sol;
// std::vector nums = {5, 1, 1, 2, 0, 0};
// std::vector sorted = sol.sortArray(nums);
// for (int num : sorted) {
// std::cout << num << " "; // 输出: 0 0 1 1 2 5
// }
// std::cout << std::endl;
// return 0;
// }
核心思想
:
优点: 时间复杂度稳定为 O(NlogN),是一种稳定的排序算法。
应用
:
nums[i]
大于右子数组的元素
nums[j]
时,
nums[i]
与右子数组中从
j
到末尾的所有元素都构成逆序对。
C++
#include
#include
class Solution {
private:
int mergeSort(std::vector& nums, std::vector& tmp, int l, int r) {
if (l >= r) {
return 0;
}
int mid = l + (r - l) / 2;
int inv_count = mergeSort(nums, tmp, l, mid) + mergeSort(nums, tmp, mid + 1, r);
int i = l, j = mid + 1, pos = l;
while (i <= mid && j <= r) {
if (nums[i] <= nums[j]) {
tmp[pos++] = nums[i++];
} else {
tmp[pos++] = nums[j++];
inv_count += (mid - i + 1);
}
}
while (i <= mid) tmp[pos++] = nums[i++];
while (j <= r) tmp[pos++] = nums[j++];
std::copy(tmp.begin() + l, tmp.begin() + r + 1, nums.begin() + l);
return inv_count;
}
public:
int reversePairs(std::vector& nums) {
if (nums.empty()) return 0;
std::vector tmp(nums.size());
return mergeSort(nums, tmp, 0, nums.size() - 1);
}
};
// int main() {
// Solution sol;
// std::vector nums = {7, 5, 6, 4};
// std::cout << sol.reversePairs(nums) << std::endl; // 输出: 5
// return 0;
// }
BFS 是一种图遍历算法,从一个起点开始,逐层向外探索。它非常适合解决最短路径问题(在边权为1的图中)。
核心数据结构: 队列 (Queue)。
算法流程
:
应用
:
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的二维网格,计算岛屿的数量。
C++
#include
#include
#include
class Solution {
public:
int numIslands(std::vector>& grid) {
if (grid.empty() || grid[0].empty()) {
return 0;
}
int m = grid.size();
int n = grid[0].size();
int count = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == '1') {
count++;
bfs(grid, i, j);
}
}
}
return count;
}
private:
void bfs(std::vector>& grid, int r, int c) {
int m = grid.size();
int n = grid[0].size();
std::queue> q;
q.push({r, c});
grid[r][c] = '0'; // Mark as visited
int dr[] = {-1, 1, 0, 0};
int dc[] = {0, 0, -1, 1};
while (!q.empty()) {
auto [currentRow, currentCol] = q.front();
q.pop();
for (int i = 0; i < 4; ++i) {
int newRow = currentRow + dr[i];
int newCol = currentCol + dc[i];
if (newRow >= 0 && newRow < m && newCol >= 0 && newCol < n && grid[newRow][newCol] == '1') {
q.push({newRow, newCol});
grid[newRow][newCol] = '0'; // Mark as visited
}
}
}
}
};
// int main() {
// Solution sol;
// std::vector> grid = {
// {'1','1','0','0','0'},
// {'1','1','0','0','0'},
// {'0','0','1','0','0'},
// {'0','0','0','1','1'}
// };
// std::cout << sol.numIslands(grid) << std::endl; // 输出: 3
// return 0;
// }
O(1)
时间复杂度的插入和查找操作,是“用空间换时间”策略的典范。
适用于需要快速查找元素是否存在或映射关系的场景。
给定一个整数数组 nums
和一个目标值 target
,请你在该数组中找出和为目标值的那两个整数,并返回它们的数组下标。
C++
#include
#include
#include
class Solution {
public:
std::vector twoSum(std::vector& nums, int target) {
std::unordered_map hash; //
for (int i = 0; i < nums.size(); ++i) {
int complement = target - nums[i];
if (hash.count(complement)) {
return {hash[complement], i};
}
hash[nums[i]] = i;
}
return {}; // No solution found
}
};
// int main() {
// Solution sol;
// std::vector nums = {2, 7, 11, 15};
// std::vector result = sol.twoSum(nums, 9);
// for (int i : result) {
// std::cout << i << " "; // 输出: 0 1
// }
// std::cout << std::endl;
// return 0;
// }