当前位置: 首页 > news >正文

位运,模拟,分治,BFS,栈和哈希表


位运算 (Bit Manipulation)

位运算直接操作二进制位,效率极高,常用于实现哈希、状态压缩和整数的特殊计算。

  • 核心思想:

    • 异或 ^: 核心性质是 a ^ a = 0a ^ 0 = a。这个“消消乐”的特性在寻找只出现一次或两次的数字时非常有效。
    • &: 常用于检查某一位是否为1。例如,x & 1 可以判断 x 的最低位。
    • 位图: 用一个整数的每一位来表示一个元素是否存在。例如,一个 int (32位) 可以表示32个不同元素的存在状态,极大地节省了空间。
  • 经典应用场景:

    判断字符唯一性
    利用位图,将每个字符映射到一个比特位,如果某位已被设置,则说明字符重复。
    寻找缺失数字
    [0, n]
    

    的完整序列和残缺数组的所有数字进行异或操作,最终结果即为缺失的数字。

    无加减法求和
    使用
    a ^ b
    

    计算无进位和,

    (a & b) << 1
    

    计算进位,循环直至进位为0。

    寻找出现特定次数的数字
    统计所有数字在每一位上出现的总次数,对次数取模 (例如,出现3次的数字,我们就对3取模),根据结果构建出那个特殊的数字。

经典例题:两整数之和 (LeetCode 371)

不使用 +- 运算符,计算两个整数 ab 的和。

C++

#include <iostream>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;
// }

模拟 (Simulation)

模拟题要求根据题意,将现实或抽象的过程用代码实现。这类问题通常不涉及复杂的算法,但对代码的实现能力和细节处理要求很高。

  • 核心思想: 准确理解题目描述的每一个规则和约束,将过程分解为清晰的步骤,并用代码逻辑一一对应。

  • 关键点

    :

    边界条件
    充分考虑输入为空、长度为1等特殊情况。
    • 状态变量: 使用合适的变量来跟踪过程中的状态变化(例如,行号、方向、计数器等)。

    规律发现
    对于看似复杂的模拟,尝试从小规模的例子入手,画图分析,寻找其中的周期性或数学规律,可以极大简化代码。

经典例题:N 字形变换 (LeetCode 6)

将一个字符串 s 按给定的行数 numRows 进行 Z 字形排列,然后按行读取输出。

C++

#include <iostream>
#include <string>
#include <vector>class Solution {
public:std::string convert(std::string s, int numRows) {if (numRows == 1) return s;std::vector<std::string> 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;
// }

分治 (Divide and Conquer)

分治是一种将大问题分解为若干个规模更小但结构相同的子问题,递归地解决这些子问题,然后将子问题的解合并以得到原问题的解的策略。快速排序归并排序是其经典应用。

1. 快速排序 (Quick Sort)

  • 核心思想 (三路快排)

    :

    1. Partition (分割): 选取一个基准元 (pivot),通常随机选取以避免最坏情况。 将数组分为三部分:小于pivot、等于pivot、大于pivot。
    2. Recursion (递归): 对小于pivot和大于pivot的两部分递归地进行快速排序。
  • 优点: 平均时间复杂度为 O(NlogN),通常是实际应用中最快的内排序算法。

  • 应用

    :

    • 排序数组: 完整的快排流程。
    • 快速选择 (Quick Select): 查找第K大/小的元素。通过Partition操作后,可以判断第K个元素在哪一个分区,然后只对该分区进行递归,将平均时间复杂度降至 O(N)。

经典例题:排序数组 (LeetCode 912)

C++

#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>class Solution {
private:// 荷兰国旗问题(三路快排)的分割操作void qsort(std::vector<int>& 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<int> sortArray(std::vector<int>& nums) {srand(time(NULL));qsort(nums, 0, nums.size() - 1);return nums;}
};// int main() {
//     Solution sol;
//     std::vector<int> nums = {5, 1, 1, 2, 0, 0};
//     std::vector<int> sorted = sol.sortArray(nums);
//     for (int num : sorted) {
//         std::cout << num << " "; // 输出: 0 0 1 1 2 5 
//     }
//     std::cout << std::endl;
//     return 0;
// }

2. 归并排序 (Merge Sort)

  • 核心思想

    :

    Divide (分)
    总是从中间将数组分成两半,直到每个子数组只有一个元素。
    Conquer (治)
    将两个已排序的子数组合并 (Merge) 成一个更大的有序数组。
  • 优点: 时间复杂度稳定为 O(NlogN),是一种稳定的排序算法。

  • 应用

    :

    求逆序对
    在合并两个有序子数组时,可以高效地统计逆序对的数量。当左子数组的元素
    nums[i]
    

    大于右子数组的元素

    nums[j]
    

    时,

    nums[i]
    

    与右子数组中从

    j
    

    到末尾的所有元素都构成逆序对。

经典例题:数组中的逆序对 (剑指 Offer 51)

C++

#include <iostream>
#include <vector>class Solution {
private:int mergeSort(std::vector<int>& nums, std::vector<int>& 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<int>& nums) {if (nums.empty()) return 0;std::vector<int> tmp(nums.size());return mergeSort(nums, tmp, 0, nums.size() - 1);}
};// int main() {
//     Solution sol;
//     std::vector<int> nums = {7, 5, 6, 4};
//     std::cout << sol.reversePairs(nums) << std::endl; // 输出: 5
//     return 0;
// }

广度优先搜索 (BFS)

BFS 是一种图遍历算法,从一个起点开始,逐层向外探索。它非常适合解决最短路径问题(在边权为1的图中)。

  • 核心数据结构: 队列 (Queue)

  • 算法流程

    :

    1. 将起点加入队列,并标记为已访问。
    2. 当队列不为空时,取出队头节点。
    3. 将其所有未被访问的邻居节点加入队列,并标记为已访问。
    4. 重复此过程,直到队列为空。
  • 应用

    :

    层序遍历
    按层遍历树或图。
    最短路径
    在无权图中,第一次到达目标节点时所经过的层数即为最短路径长度。
    多源BFS
    将所有源点同时入队,可以同时开始搜索,常用于求解所有点到最近源点的距离。
    拓扑排序
    用于检测有向无环图 (DAG) 中的依赖关系。首先将所有入度为0的节点入队,然后不断取出节点,并将其邻居节点的入度减1,若邻居入度变为0则入队。

经典例题:岛屿数量 (LeetCode 200)

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的二维网格,计算岛屿的数量。

C++

#include <iostream>
#include <vector>
#include <queue>class Solution {
public:int numIslands(std::vector<std::vector<char>>& 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<std::vector<char>>& grid, int r, int c) {int m = grid.size();int n = grid[0].size();std::queue<std::pair<int, int>> q;q.push({r, c});grid[r][c] = '0'; // Mark as visitedint 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<std::vector<char>> 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;
// }

栈 (Stack) 与 哈希表 (Hash Table)

栈 (Stack)
一种后进先出 (LIFO) 的数据结构,非常适合处理具有递归结构或需要“撤销”操作的问题,如括号匹配、退格符处理等。
哈希表 (Hash Table)
提供平均

O(1)

时间复杂度的插入和查找操作,是“用空间换时间”策略的典范。

适用于需要快速查找元素是否存在或映射关系的场景。

组合使用
两者结合可以解决更复杂的问题。例如,在处理嵌套结构(如字符串解码)时,可以用栈来保存外层的状态(数字和字符串),在内层解码完成后再恢复。

经典例题:两数之和 (LeetCode 1)

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回它们的数组下标。

C++

#include <iostream>
#include <vector>
#include <unordered_map>class Solution {
public:std::vector<int> twoSum(std::vector<int>& nums, int target) {std::unordered_map<int, int> hash; // <number, index>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<int> nums = {2, 7, 11, 15};
//     std::vector<int> result = sol.twoSum(nums, 9);
//     for (int i : result) {
//         std::cout << i << " "; // 输出: 0 1
//     }
//     std::cout << std::endl;
//     return 0;
// }

相关文章:

  • 基于 C 语言的图书管理系统开发详解​
  • 人工智能学习14-Numpy-数组广播机制
  • 前端异步编程基础
  • pythonday46
  • HTML+CSS 动态背景动态登录注册框
  • 模拟 AJAX 提交 form 表单及请求头设置详解
  • 大模型成长过程-预训练tokenizer
  • SQL Server 窗口函数详解:窗口行数控制的原理、关键字与应用场景
  • 鸿蒙NEXT-HMRouter,在使用router后无法跳转问题解决
  • 计算机网络-自顶向下—第四章网络层重点复习笔记
  • Python实例题:Python计算偏微分方程
  • 【Ubuntu 22.04 推荐的 apt 包管理方式详解】
  • HQL 优化:从低效到高效的蜕变之旅
  • Git可视化革命:3分钟学会用Mermaid+AI画专业分支图
  • 数据治理域——数据建模设计
  • LabVIEW工业金属腐蚀监测
  • LeetCode 第71题 简化路径(繁琐)
  • 打牙祭是什么意思
  • SCADA|信创KingSCADA4.0历史报警查询的差异
  • XCTF-misc-János-the-Ripper
  • 东莞网站seo推广/集合竞价口诀背熟6句
  • 装潢设计软件免费/青岛谷歌seo
  • 八宝山网站建设/企业推广宣传方案
  • 南通网站建设推广/自己怎么给网站做优化排名
  • 公司网站建设价格多少/南京seo网站优化
  • 做网站的属于什么行业/seo优化方向