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

Python、C++中的查找

一、Python 中的查找

Python 是一门高层次语言,内置了许多便捷的查找方法,适合快速开发和验证算法思想。以下是 Python 中常见的查找方式:

1. 线性查找(Linear Search)

原理

  • 线性查找是最简单的查找方法,逐一检查数据集合中的每个元素,直到找到目标元素或遍历完整个集合。
  • 适用于无序或有序数据。

实现

def linear_search(arr, target):
    for i in range(len(arr)):
        if arr[i] == target:
            return i  # 返回目标元素的索引
    return -1  # 未找到返回-1

# 示例
arr = [4, 2, 7, 1, 9]
target = 7
print(linear_search(arr, target))  # 输出:2

复杂度

  • 时间复杂度: O ( n ) O(n) O(n),其中 n 是数组长度。
  • 空间复杂度: O ( 1 ) O(1) O(1)

竞赛中的应用

  • 适合数据规模较小(n ≤ 10^3)或无序数据。
  • 常用于简单问题或作为其他复杂算法的子步骤。

Python 特性

  • Python 提供了内置的 in 运算符和 index() 方法,实际上是线性查找的封装:
    if target in arr:
        print(arr.index(target))  # 输出目标索引
    else:
        print(-1)
    
  • 注意:index() 如果未找到目标会抛出 ValueError,需处理异常。

2. 二分查找(Binary Search)

原理

  • 二分查找适用于有序数组,通过不断将查找范围折半来定位目标元素。
  • 每次比较中间元素,将查找范围缩小到左半部分或右半部分。

实现

def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    while left <= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return -1

# 示例
arr = [1, 2, 4, 7, 9]  # 必须是有序的
target = 7
print(binary_search(arr, target))  # 输出:3

复杂度

  • 时间复杂度: O ( l o g n ) O(log n) O(logn),效率远高于线性查找。
  • 空间复杂度: O ( 1 ) O(1) O(1)(迭代实现); O ( l o g n ) O(log n) O(logn)(递归实现,因调用栈)。

竞赛中的应用

  • 常用于处理有序数据或需要快速定位元素的问题。
  • 二分查找还可以扩展到“二分答案”技巧,解决优化问题(如最小化最大值)。
  • 示例问题:查找一个数是否存在、寻找上下界(如 bisect 模块的应用)。

Python 特性

  • Python 的 bisect 模块提供了高效的二分查找工具:
    import bisect
    arr = [1, 2, 4, 7, 9]
    print(bisect.bisect_left(arr, 7))  # 输出:3(目标的插入位置)
    print(bisect.bisect_right(arr, 7)) # 输出:4(目标右侧插入位置)
    
  • bisect_leftbisect_right 分别用于寻找左边界和右边界,适合处理重复元素。

3. 哈希表查找(Hash Table Search)

原理

  • 使用哈希表(Python 中的 dictset)存储数据,键值映射允许近似 O(1) 的查找。
  • 适合无序数据,特别是有大量查询的场景。

实现

def hash_search(arr, target):
    hash_map = {x: i for i, x in enumerate(arr)}  # 存储值到索引的映射
    return hash_map.get(target, -1)  # 返回索引或-1

# 示例
arr = [4, 2, 7, 1, 9]
target = 7
print(hash_search(arr, target))  # 输出:2

复杂度

  • 时间复杂度:平均 O ( 1 ) O(1) O(1),最坏 O ( n ) O(n) O(n)(因哈希冲突)。
  • 空间复杂度: O ( n ) O(n) O(n),需要额外存储哈希表。

竞赛中的应用

  • 适合需要快速判断元素是否存在或统计出现次数的问题。
  • 示例问题:两数之和、子数组和等于某个值等。
  • Python 的 setdict 是竞赛中常用的高效工具:
    hash_set = set(arr)
    if target in hash_set:
        print("Found")
    

4. 其他查找方法

  • 内置函数:Python 的 list.count() 可统计元素出现次数,list.index() 可查找第一个匹配的索引。
  • 集合操作:对于多集合查询,可以用 set 的交集、并集操作。
  • 高级数据结构:如 collections.Counter 用于计数,sortedcontainers.SortedList 用于动态维护有序序列。

二、C++ 中的查找

C++ 是一门性能更高的语言,提供了底层控制能力和标准模板库(STL),在算法竞赛中非常流行。以下是 C++ 中常见的查找方法:

1. 线性查找(Linear Search)

原理

  • 与 Python 类似,逐一遍历数组元素。

实现

#include <iostream>
#include <vector>
using namespace std;

int linear_search(vector<int>& arr, int target) {
    for (int i = 0; i < arr.size(); ++i) {
        if (arr[i] == target) {
            return i;
        }
    }
    return -1;
}

int main() {
    vector<int> arr = {4, 2, 7, 1, 9};
    int target = 7;
    cout << linear_search(arr, target) << endl; // 输出:2
    return 0;
}

复杂度

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)

竞赛中的应用

  • 适用于小规模数据或无序数组。
  • 注意:C++ 中需手动处理数组越界问题。

2. 二分查找(Binary Search)

原理

  • 与 Python 类似,针对有序数组进行折半查找。

实现

#include <iostream>
#include <vector>
using namespace std;

int binary_search(vector<int>& arr, int target) {
    int left = 0, right = arr.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2; // 防止溢出
        if (arr[mid] == target) {
            return mid;
        } else if (arr[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return -1;
}

int main() {
    vector<int> arr = {1, 2, 4, 7, 9};
    int target = 7;
    cout << binary_search(arr, target) << endl; // 输出:3
    return 0;
}

复杂度

  • 时间复杂度: O ( l o g n ) O(log n) O(logn)
  • 空间复杂度: O ( 1 ) O(1) O(1)(迭代实现)。

竞赛中的应用

  • 常用于有序数据查找或二分答案。
  • C++ 的 STL 提供了高效的二分查找函数:
    #include <algorithm>
    auto it = lower_bound(arr.begin(), arr.end(), target); // 左边界
    if (it != arr.end() && *it == target) {
        cout << distance(arr.begin(), it) << endl;
    }
    
  • lower_boundupper_bound 可处理重复元素,binary_search 可快速判断元素是否存在。

注意

  • 使用 STL 时,数组必须有序。
  • mid = left + (right - left) / 2(left + right) / 2 更安全,避免整数溢出。

3. 哈希表查找(Hash Table Search)

原理

  • 使用 unordered_mapunordered_set 实现高效键值查找。

实现

#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

int hash_search(vector<int>& arr, int target) {
    unordered_map<int, int> hash_map;
    for (int i = 0; i < arr.size(); ++i) {
        hash_map[arr[i]] = i;
    }
    if (hash_map.count(target)) {
        return hash_map[target];
    }
    return -1;
}

int main() {
    vector<int> arr = {4, 2, 7, 1, 9};
    int target = 7;
    cout << hash_search(arr, target) << endl; // 输出:2
    return 0;
}

复杂度

  • 时间复杂度:平均 O ( 1 ) O(1) O(1),最坏 O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

竞赛中的应用

  • 适合需要快速查询或计数的场景。
  • 示例:两数之和、判断子序列等。
  • unordered_set 用于快速判断元素是否存在:
    #include <unordered_set>
    unordered_set<int> hash_set(arr.begin(), arr.end());
    if (hash_set.count(target)) {
        cout << "Found" << endl;
    }
    

注意

  • C++ 的 unordered_mapunordered_set 可能因哈希冲突导致性能下降。
  • 如果需要确定性性能,可使用 mapset(基于红黑树, O ( l o g n ) O(log n) O(logn))。

4. 其他查找方法

  • STL 算法
    • find:线性查找,适用于任意容器。
      auto it = find(arr.begin(), arr.end(), target);
      if (it != arr.end()) {
          cout << distance(arr.begin(), it) << endl;
      }
      
    • count:统计元素出现次数。
  • 高级数据结构
    • setmap:基于红黑树,适合动态维护有序数据。
    • priority_queue:间接用于某些查找最大/最小值的问题。
    • 第三方库(如 policy-based data structures)提供动态有序集合,需手动引入。

三、Python vs. C++ 查找的对比

特性PythonC++
线性查找简单,in 运算符封装,易用手动实现,需注意越界,性能更高
二分查找bisect 模块高效,代码简洁STL 提供 lower_bound 等,性能优
哈希表查找dictset 内置,开发效率高unordered_map/set 性能高,需手动
运行效率解释型语言,运行较慢编译型语言,运行极快
开发效率代码简洁,内置工具多,适合快速验证代码较繁琐,STL 功能强大
竞赛适用场景适合中小规模数据,快速原型适合大规模数据,严格时间限制

四、竞赛中的注意事项和技巧

  1. 选择合适的查找方法

    • 数据规模小 n ≤ 1 0 3 n ≤ 10^3 n103:线性查找足够。
    • 数据有序且规模大 n ≤ 1 0 6 n ≤ 10^6 n106:优先二分查找。
    • 需要快速查询或计数:哈希表是首选。
    • 动态数据:考虑平衡树(如 C++ 的 set 或 Python 的 SortedList)。
  2. 预处理与优化

    • 如果数据不变,先排序后用二分查找。
    • 使用哈希表缓存结果,减少重复计算。
    • 对于多查询问题,优先构建哈希表或前缀和。
  3. 边界问题

    • 二分查找时注意 left <= rightmid 的计算。
    • C++ 中注意数组越界,Python 中注意异常处理。
  4. 语言特性利用

    • Python:善用 bisectcollections.Counter 等模块。
    • C++:熟练使用 STL 的 lower_boundunordered_map 等。
  5. 调试与验证

    • 构造边界用例(如空数组、目标不存在、重复元素)。
    • 使用小数据手动验证查找逻辑。

五、示例竞赛问题与解法

问题 1:查找元素是否存在

题目:给定一个数组和目标值,判断目标值是否在数组中。
Python 解法

def exists(arr, target):
    return target in arr  # 线性查找

C++ 解法

#include <unordered_set>
bool exists(vector<int>& arr, int target) {
    unordered_set<int> s(arr.begin(), arr.end());
    return s.count(target);
}

问题 2:查找第一个大于等于目标值的索引

题目:给定有序数组,找到第一个 ≥ target 的元素索引。
Python 解法

import bisect
def find_first_ge(arr, target):
    return bisect.bisect_left(arr, target)

C++ 解法

#include <algorithm>
int find_first_ge(vector<int>& arr, int target) {
    auto it = lower_bound(arr.begin(), arr.end(), target);
    return distance(arr.begin(), it);
}

相关文章:

  • Spring Bean的创建过程与三级缓存的关系详解
  • socket到底是什么
  • 分发饼干问题——用贪心算法解决
  • Oracle 11G RAC 删除添加节点(一):删除节点
  • 智能SEO关键词AI精准布局
  • swagger 注释说明
  • LeetCode 34 在排序数组中查找元素的第一个和最后一个位置
  • 【5G学习】5G中常说的上下文之上下文响应
  • 在线地图支持天地图和腾讯地图,仪表板和数据大屏支持发布功能,DataEase开源BI工具v2.10.7 LTS版本发布
  • java中的Future的设计模式 手写一个简易的Future
  • C语言 ——— 认识C语言
  • 应对海量数据归档难题?AWS Glacier 的低成本冷存储解决方案实践指南
  • Keras使用1
  • 【AI学习从零至壹】语⾔模型及词向量相关知识
  • linux多线(进)程编程——(6)共享内存
  • 链表代码实现(C++)
  • C语言--常见的编程示例
  • 医药采购系统平台第5天01:药品目录导入功能的实现Oracle触发器的定义供货商药品目录模块的分析供货商目录表和供货商控制表的分析、数据模型设计和优化
  • Rasa 模拟实现超简易医生助手(适合初学练手)
  • Tkinter表格与列表框应用
  • 媒体:酒店、民宿临时毁约涨价,怎么管?
  • 水利部将联合最高检开展黄河流域水生态保护专项行动
  • 中青旅:第一季度营业收入约20.54亿元,乌镇景区接待游客数量同比减少6.7%
  • 宋徽宗《芙蓉锦鸡图》亮相,故宫首展历代动物绘画
  • 五月院线片单:就看五一档表现了
  • 李在明涉嫌违反《公职选举法》案将于5月1日宣判