算法与数据结构(1.4):divide and conquer 分治法 (six questions, c++)

本文介绍了分治法在算法中的应用,通过六个典型问题(二分查找、主要元素、改进快速排序、逆序对计数、彩票组织、最近点对)阐述分治策略。详细讲解了每个问题的解决方案,并提供了C++代码实现,旨在帮助理解分治法的核心思想和优化技巧。
摘要由CSDN通过智能技术生成

分治法一直以来是算法中的经典,难度介于贪心和动态规划之间,本次就来分享一下分治法中非常有代表性的六道题。

Q1:  Binary Search


二分查找应该是分治法应用中最基本的算法了,相对于普通查找时间复杂度 O(n) 来说,二分查找的时间复杂度为 O(logn) ,这大大提升了查找的效率。
#include <iostream>
#include <cassert>
#include <vector>

using namespace std;

int binary_search(const vector<int> &a, int x) {
  int low = 0, high = (int)a.size(); 
  int mid;
  while(low <= high){
    mid = (low + high) / 2;
    if(x == a[mid]) return mid;
    else if(x < a[mid]) high = mid - 1;
    else low = mid + 1;
  }
  return -1;
}

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

int main() {
  int n;
  std::cin >> n;
  vector<int> a(n);
  for (size_t i = 0; i < a.size(); i++) {
    std::cin >> a[i];
  }
  int m;
  std::cin >> m;
  vector<int> b(m);
  for (int i = 0; i < m; ++i) {
    std::cin >> b[i];
  }
  for (int i = 0; i < m; ++i) {
    std::cout << binary_search(a, b[i]) << ' ';
  }
}

以上就是线性查找和二分查找的基本步骤,还是比较简单的。

二分查找的基本思路就是:首先我们对要查找的数组排序,然后不断比较中间元素与查找值得大小来判断查找的指针该向哪边移动:

如果中间值小于查找值,那就只需要搜索右半区;

如果中间值大于查找值,那就只需要搜索左半区;

这样不断迭代,最后找到想找的那个元素。


Q2: Majority Elements


主要元素这个问题说的是我们要从n个元素中找到一个元素,它出现的次数超过一半,如果找不到那就输出0。

只要会写程序语言,应该能想出尚若我们统计每个元素出现的次数,统计出出现次数大于n/2的,便解决了这个问题。但是复杂度为O(n^2),我们能不能想出一种更快的方法呢?

答案就是使用分治法:

我们将一个数组分为左右半区,如果一个元素是整个数组的主要元素,那么它一定也是左半区或者右半区的主要元素,不然个数不可能超过n/2。假设我们已经得到了左右半区的主要元素(如果哪个半区没有主要元素,则返回值为-1),下面就是如何合并。我们将左右半区合起来,数出左半区主要元素或者右半区主要元素出现的次数是否超过这整个区的一半,谁超过就返回谁。如果都没有超过,就返回-1。

最后输出是判断有无主要元素。

下面是代码:

#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

int get_majority_element(vector<int> &a, int left, int right) {
  if (left == right) return -1;
  if (left + 1 == right) return a[left];
  //write your code here
  int mid = (left + right) / 2;
  int low = get_majority_element(a, left, mid);
  int high = get_majority_elem
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值