1152 Analyze User Website Visit Pattern 用戶網站訪問行為分析
描述
為了評估某網站的用戶轉化率,我們需要對用戶的訪問行為進行分析,並建立用戶行為模型。
日志文件
中已經記錄了用戶名
、訪問時間
以及頁面路徑
。
為了方便分析,日志文件中的 N 條記錄已經被解析成三個長度相同且長度都為 N 的數組,分別是:用戶名 username
,訪問時間 timestamp
和 頁面路徑 website
。第 i 條記錄意味着用戶名是 username[i] 的用戶在 timestamp[i] 的時候訪問了路徑為 website[i] 的頁面。
我們需要找到用戶訪問網站時的 『共性行為路徑』
,也就是有最多的用戶都 至少按某種次序訪問過一次 的三個頁面路徑。需要注意的是,用戶 可能不是連續訪問 這三個路徑的。
『共性行為路徑』是一個 長度為 3 的頁面路徑列表,列表中的路徑 不必不同,並且按照訪問時間的先后升序排列。
如果有多個滿足要求的答案,那么就請返回按字典序排列最小的那個。
(頁面路徑列表 X 按字典序小於 Y 的前提條件是:X[0] < Y[0] 或 X[0] == Y[0] 且 (X[1] < Y[1] 或 X[1] == Y[1] 且 X[2] < Y[2]))
題目保證一個用戶會至少訪問 3 個路徑一致的頁面,並且一個用戶不會在同一時間訪問兩個路徑不同的頁面。
- 示例:
輸入:username = ["joe","joe","joe","james","james","james","james","mary","mary","mary"],
timestamp = [1,2,3,4,5,6,7,8,9,10],
website = ["home","about","career","home","cart","maps","home","home","about","career"]
輸出:["home","about","career"]
解釋:
由示例輸入得到的記錄如下:
["joe", 1, "home"]
["joe", 2, "about"]
["joe", 3, "career"]
["james", 4, "home"]
["james", 5, "cart"]
["james", 6, "maps"]
["james", 7, "home"]
["mary", 8, "home"]
["mary", 9, "about"]
["mary", 10, "career"]
有 2 個用戶至少訪問過一次 ("home", "about", "career")。
有 1 個用戶至少訪問過一次 ("home", "cart", "maps")。
有 1 個用戶至少訪問過一次 ("home", "cart", "home")。
有 1 個用戶至少訪問過一次 ("home", "maps", "home")。
有 1 個用戶至少訪問過一次 ("cart", "maps", "home")。
- 提示:
3 <= N = username.length = timestamp.length = website.length <= 50
1 <= username[i].length <= 10
0 <= timestamp[i] <= 10^9
1 <= website[i].length <= 10
username[i] 和 website[i] 都只含小寫字符
思路
暴力枚舉每個用戶的順序網頁訪問路徑
(有三個頁面)
選出訪問路徑
出現最多次數的那個 或者 字典序排列最小的那個
代碼實現
重要存儲結構示意圖如下:
暴力枚舉每一用戶訪問路徑並投票
class Solution {
public List<String> mostVisitedPattern(String[] username, int[] timestamp, String[] website) {
// utwRecords 根據用戶名username組合三個數組 <username, <timestamp, website>>
// 注意內部使用TreeMap 是為了排序 時間戳timestamp的按順序排列
HashMap<String, TreeMap<Integer, String>> utwRecords = new HashMap<>();
for (int i = 0; i < username.length; i++) {
if (!utwRecords.containsKey(username[i])) {
utwRecords.put(username[i], new TreeMap<Integer, String>());
}
utwRecords.get(username[i]).put(timestamp[i], website[i]);
}
// uwRecords 提取utwRecords中除時間戳timestamp的數據
// 用戶名username以及對應訪問的網頁website(按時間戳排序)
HashMap<String, ArrayList<String>> uwRecords = new HashMap<>();
for (String name : utwRecords.keySet()) {
uwRecords.put(name, new ArrayList<String>());
for (Integer time : utwRecords.get(name).keySet()) {
uwRecords.get(name).add(utwRecords.get(name).get(time));
}
}
// cntWP 存儲所枚舉的每一條網頁訪問路徑 並計錄其出現的次數
// <網頁訪問路徑(3個網頁名稱合成1條字符串), 出現次數>
HashMap<String, Integer> cntWP = new HashMap<>();
// maxCnt 網頁訪問路徑出現最多次數為
int maxCnt = 0;
// res 最多次數的網頁訪問路徑(3個網頁名稱合成1條字符串)
String res = new String();
for (String name : uwRecords.keySet()) {
// len 當前用戶所訪問的網頁數
int len = uwRecords.get(name).size();
// single 存儲當前用戶所訪問網頁的訪問路徑 並去重
HashSet<String> single = new HashSet<>();
for (int i = 0; i < len-2; i++) {
for (int j = i+1; j < len-1; j++) {
for (int k = j+1; k < len; k++) {
// 網頁訪問路徑格式: A-->B-->C
String cur = (new StringBuilder()).append(uwRecords.get(name).get(i))
.append("->")
.append(uwRecords.get(name).get(j))
.append("->")
.append(uwRecords.get(name).get(k)).toString();
single.add(cur);
}
}
}
// 遍歷當前用戶所訪問網絡的路徑 存儲並給訪問路徑計數
for (String str : single) {
if (!cntWP.containsKey(str)) {
cntWP.put(str, 0);
}
cntWP.put(str, cntWP.get(str)+1);
int curCnt = cntWP.get(str);
// 當該訪問路徑出現次數curCnt大於最大訪問次數maxCnt
// 那么結果路徑res就是該路徑
// 或者
// 當該訪問路徑出現次數curCnt等於最大訪問次數maxCnt 且字典序小於原出現次數最多的路徑res
// 那么結果路徑res就是該路徑
if (curCnt > maxCnt | (curCnt == maxCnt && str.compareTo(res) < 0)) {
maxCnt = curCnt;
res = str;
}
}
}
// ans 存儲所求結果訪問路徑的3個網頁
// 其實也可以使用 Arrays.asList(res.split("->"))
ArrayList<String> ans = new ArrayList<>();
for (String str : res.split("->")) {
ans.add(str);
}
return ans;
}
}