求找出N個格子中前m個的最多人走過的格子??
阿新 • • 發佈:2019-01-11
題目:
對於一個區域中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問題,是否可以轉換為樹的大頂錐問題;