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