算法----序列和的 top N
Description:
两个长度为 n 的数组 A 和 B, 各从中选出一个元素相加 A[i] + B[j], 求 top n 小的那些和。
思路 1:这样的和总共有 n^2 个, 排序,然后取前 n 个。
时间复杂度 O(n^2 lgn), 空间复杂度 O(n^2)
思路 2:用 最大堆。
1. 首先用 n 个和建立一个最大堆,
2. 然后循环剩余的 n^2 - n 个和,依次与堆顶元素比较(最大值), 如果小于最大值,则弹出堆顶,push 进入当前的和。
时间复杂度 O(n^2 lgn), 空间复杂度是 O(n)
思路3: 还是采用 最小堆,并采用 多路合并 的思路。
首先,分析多路合并问题: 把 K 个有序数组合并成一个数组。
1. 将 K 个数组的首元素(最小),建立一个最小堆;
2. 弹出最小值,并插入新的数组中;将最小值所在的数组的下一个元素插入堆中。这样依次执行下去。
多路合并的代码见 http://blog.csdn.net/shoulinjun/article/details/19576585
回到我们的问题,将 N^2 个 sum 写成如下的形式:
所有 N^2 个和:(数组 A 和 B 排序后)
A[0] + B[0] <= A[0] + B[1] <= A[0] + B[2] <= ... <= A[0] + B[n-1]
A[1] + B[0] <= A[1] + B[1] <= A[1] + B[2] <= ... <= A[1] + B[n-1]
...............................
A[n-1] + B[0] <= A[n-1] + B[1] <= A[n-1] + B[2] <= ... <= A[n-1] + B[n-1]
注意: 第一步将数组 A 和 B 排序,则上述的 N 个序列都是有序的。
Bingo! 这时就可以采用与 多路合并 同样的算法:
Algorithm:
1. 将数组 A 和 B 排序;
2. 用 上述 N 个序列的首元素(最小),建立一个最小堆;
3. 弹出最小值,即为 top N;将最小值所在的数组的下一个元素插入堆中。这样执行 N 次, 得到 所有的 top N。
Complexity:
O(NlgN) + O(N)+ N*O(lgN) = O(NlgN)
Implementation:
实现细节的话,算法的第 2 步中, 最小值所在的数组的下一个元素如何得到?? 可以同时记录最小值这个和中所包含的B 中元素的下标。
下一个元素的值就是 min - B[i] + B[i+1]
//copyright @ L.J.SHOU Feb.14, 2014
#include <iostream>
#include <vector>
#include <utility>
#include <queue>
#include <algorithm>
#include <iterator>
using namespace std; //A and B have the same size K
vector<int> TopKSum(vector<int> &A, vector<int> &B)
{
vector<int> result;
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > Q; /* sort */
sort(A.begin(), A.end());
sort(B.begin(), B.end()); for(int i=0; i<A.size(); ++i)
Q.push(make_pair(A[i] + B[0], 0)); /* 0 denotes index in B */ for(int i=0; i<A.size(); ++i)
{
pair<int, int> e = Q.top(); Q.pop();
result.push_back(e.first);
/* push next element back into heap */
e.first = e.first - B[e.second] + B[e.second+1];
e.second ++;
Q.push(e);
} return result;
} int main(void)
{
vector<int> A, B, sum;
A.push_back(1);
A.push_back(2);
A.push_back(3); B.push_back(2);
B.push_back(4);
B.push_back(4); sum = TopKSum(A, B);
/* print vector */
copy(sum.begin(), sum.end(), ostream_iterator<int>(cout, " "));
cout << endl; return 0;
}
思考题:
n 个长度为 n 的数组,每个数组中选出一个元素相加, 求 top n 小的那些 sum。
复杂度: n^2 lgn
算法----序列和的 top N的更多相关文章
- 【机器学习】支持向量机(SVM)的优化算法——序列最小优化算法(SMO)概述
SMO算法是一一种启发式算法,它的基本思路是如果所有变量的解的条件都满足最优化问题的KKT条件,那么这个最优化问题的解就得到了.因为KKT条件是该优化问题的充分必要条件. 整个SMO算法包括两个部分: ...
- MapReduce算法形式五:TOP—N
案例五:TOP—N 这个问题比较常见,一般都用于求前几个或者后几个的问题,shuffle有一个默认的排序是正序的,但如果需要逆序的并且暂时还不知道如何重写shuffle的排序规则的时候就用以下方法就行 ...
- 经典算法(一) top k
问题:1亿数据中,找出最大的k个数,要求使用内存不超过1m (延伸问题:1亿数据中,找出重复出现次数最多的k个,要求使用内存不超过1m 等) 分析: 1亿数字(int)占内存:100000000 * ...
- 必考算法之 Top K 问题
大家好,这里是<齐姐聊算法>系列之 Top K 问题. Top K 问题是面试中非常常考的算法题. 8 Leetcode 上这两题大同小异,这里以第一题为例. 题意: 给一组词,统计出现频 ...
- Top K问题的两种解决思路
Top K问题在数据分析中非常普遍的一个问题(在面试中也经常被问到),比如: 从20亿个数字的文本中,找出最大的前100个. 解决Top K问题有两种思路, 最直观:小顶堆(大顶堆 -> 最小1 ...
- 标签传播算法(Label Propagation Algorithm, LPA)初探
0. 社区划分简介 0x1:非重叠社区划分方法 在一个网络里面,每一个样本只能是属于一个社区的,那么这样的问题就称为非重叠社区划分. 在非重叠社区划分算法里面,有很多的方法: 1. 基于模块度优化的社 ...
- 【决战西二旗】|理解Sort算法
前言 前面两篇文章介绍了快速排序的基础知识和优化方向,今天来看一下STL中的sort算法的底层实现和代码技巧. 众所周知STL是借助于模板化来支撑数据结构和算法的通用化,通用化对于C++使用者来说已经 ...
- K-近邻算法kNN
K-近邻算法(k-Nearest Neighbor,简称kNN)采用测量不同特征值之间的距离方法进行分类,是一种常用的监督学习方法,其工作机制很简单:给定测试样本,基于某种距离亮度找出训练集中与其靠近 ...
- c++模板库(简介)
目 录 STL 简介 ......................................................................................... ...
随机推荐
- 《javascript高级程序设计》第六章 Object Creation VS Inheritance
6.1 理解对象 6.1.1 属性类型 6.1.2 定义多个属性 6.1.3 读取属性的特性6.2 创建对象 6.2.1 工厂模式 6.2.2 构造函数模式 6.2.3 原型模式 6.2.4 组合使用 ...
- [转载]Soap安全测试入门
http://www.cnblogs.com/zerotest/p/4670902.html 在SoapUI4.0引入的安全测试特点使它非常容易为你来验证你的目标服务的功能性安全,就可以评估您的系统常 ...
- (18)odoo规范
* 约定 # 命名会用 蛇形式或驼峰式 todo_task_stage 蛇形式 class TodoTask 驼峰式 变量名还是蛇形居多, 类名和方法名驼 ...
- hdu---(2604)Queuing(矩阵快速幂)
Queuing Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- 原生JavaScript实现mouseenter
mouseenter和Mouseleave都是jquery的事件,JavaScript的mouseover和mouseout每个子元素都会触发,从子元素移到父元素也会触发,用起来不很方便,而且触发的太 ...
- asp.net 奇淫技巧
VS2013自动注释插件 分享一个Visual Studio的背景插件,让堆码更富情趣 工欲善其事必先利其器系列之:更换Visual Studio代码风格. 为Visual Studio更换皮肤和背景 ...
- python中数据的变量和字符串的常用使用方法
1.查看变量类型: a=2 print(a,type(a)) print的用法:在print后面跟多个输出,可以用逗号分隔. 回收变量名,如把a存储不同的数据,你不需要删除原有变量就可以直接赋值 2. ...
- Android selector选择器的使用
通常按钮在点击前和后有两种状态,比如点击前为蓝色,点击后为灰色,且不再响应点击事件. 如果不使用selector选择器,点击后,就需要在程序中进行以下的类似操作 button1.setBackgrou ...
- js基础之弹性运动(四)
一.滑动菜单.图片 var iSpeed=0;var left=0;function startMove(obj,iTarg){ clearInterval(obj.timer);//记得先关定时器 ...
- LCA-倍增法(在线)
原文:http://www.tuicool.com/articles/N7jQV32 1. DFS预处理出所有节点的深度和父节点 inline void dfs(int u) { int i; for ...