题目:
对于一个区域中N个地理格子,给定很多人走过的轨迹,求找出N个格子中前m个最多人走过的格子??
实现:
package grid.geo;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Map.Entry;
import cetc.ocean.common.geohash.GeoHash;
/**
* 描述:对于一个区域中N个地理格子,给定很多人走过的轨迹orignGrid ,求找出N个格子中前m个最多人走过的格子??
* @author: fangchangtan
* @version 创建时间:2018年12月19日 下午1:56:24
*/
public class GridCountTop {
//orignGrid 表示原始N个格子,此处使用geohash代替
String orignGrid ="geohash1,geohash2,....";
//初始化读取orignGrid 格子到缓存中
static HashSet<String> setInitGridNum = new HashSet<>();
//历史轨迹点,存入有序集合中
ArrayList<TrackPointBean> trackHistory = new ArrayList<>();
//mapTrackPoints 表示辅助缓存:HashSet自动过滤掉重复的人
Map<String, HashSet<Integer>> mapTrackPoints = new HashMap<>();
public static void main(String[] args) {
GridCountTop gridCountTop = new GridCountTop();
gridCountTop.initGrid();
List<String> gridTopN = gridCountTop.getGridTopN(5);
for (String geohash : gridTopN) {
System.out.println("N个格子中前m个最多人走过的格子geohash为:"+geohash);
}
}
/*读取初始N个格子
*/
public void initGrid() {
String[] split = orignGrid.split(",");
for (String grid : split) {
setInitGridNum.add(grid);
}
System.out.println("orign grid num:"+setInitGridNum.size());
//初始化轨迹缓存trackHistory
//........
}
/*topN 表示:前m个格子
*/
public List<String> getGridTopN(int topN ) {
for (TrackPointBean trackPointBean : trackHistory) {
int userId = trackPointBean.getUserId();
String curr_geohash5 = GeoHash.geoHashStringWithCharacterPrecision(trackPointBean.getLat(), trackPointBean.getLon(), 5);
if (setInitGridNum.contains(curr_geohash5)) {
if (mapTrackPoints.containsKey(curr_geohash5)) {
mapTrackPoints.get(curr_geohash5).add(userId);
}else {
mapTrackPoints.put(curr_geohash5,new HashSet<Integer>(){{add(userId);}});
}
}
}
TreeSet<KeyBean> treeSet = new TreeSet<>();
for (Entry<String, HashSet<Integer>> entry : mapTrackPoints.entrySet()) {
int size = entry.getValue().size();
String geohash5 = entry.getKey();
KeyBean keyBean = new KeyBean(size, geohash5);
treeSet.add(keyBean);
}
ArrayList<String> arrayList = new ArrayList<>();
if (treeSet.size() > topN) {
Iterator<KeyBean> iterator = treeSet.iterator();
for (int i = 0; i < topN; i++) {
arrayList.add(iterator.next().getGeohash());
}
}else {
Iterator<KeyBean> iterator = treeSet.iterator();
while (iterator.hasNext()) {
arrayList.add(iterator.next().getGeohash());
}
}
return arrayList;
}
/*自定义从大到小的类比较器
*/
class KeyBean implements Comparator<KeyBean> {
int num;
String geohash;
public KeyBean(int num, String geohash) {
super();
this.num = num;
this.geohash = geohash;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getGeohash() {
return geohash;
}
public void setGeohash(String geohash) {
this.geohash = geohash;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + ((geohash == null) ? 0 : geohash.hashCode());
result = prime * result + num;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
KeyBean other = (KeyBean) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (geohash == null) {
if (other.geohash != null)
return false;
} else if (!geohash.equals(other.geohash))
return false;
if (num != other.num)
return false;
return true;
}
//逆序输出
@Override
public int compare(KeyBean o1, KeyBean o2) {
// TODO Auto-generated method stub
if (o1.getNum() != o2.getNum()) {
return o2.getNum()-o1.getNum();
}else {
return o2.getGeohash().compareTo(o1.getGeohash());
}
}
}
/*自定义轨迹点
*/
class TrackPointBean {
private int userId;
private double lon;
private double lat;
private double utc;
public TrackPointBean(int userId, double lon, double lat, double utc) {
super();
this.userId = userId;
this.lon = lon;
this.lat = lat;
this.utc = utc;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public double getLon() {
return lon;
}
public void setLon(double lon) {
this.lon = lon;
}
public double getLat() {
return lat;
}
public void setLat(double lat) {
this.lat = lat;
}
public double getUtc() {
return utc;
}
public void setUtc(double utc) {
this.utc = utc;
}
@Override
public String toString() {
return "TrackPointBean [userId=" + userId + ", lon=" + lon + ", lat=" + lat + ", utc=" + utc + "]";
}
}
}
写完代码我们看一下代码的算法复杂度:
第一步:遍历所有的轨迹点(数量为P),存入mapTrackPoints中;
第二步:遍历mapTrackPoints的结果中value和key反向解析组合成KeyBean后存入TreeSet(大小为Q)中(倒叙输出);这时候直接取出前N个至就行了;
算法复杂度为P+Q+N;
存在的问题:
1.没有考虑相邻轨迹点同是跨过N个格子的问题;比如从第1格直接跳到第3个格子的问题;
2.这种依靠java中集合来实现的功能并不是最有的,前N问题,是否可以转换为树的大顶锥问题;