如何在java页面序列的练习中获得更好的时间复杂度

如何在java页面序列的练习中获得更好的时间复杂度,java,algorithm,big-o,Java,Algorithm,Big O,问题是: 条目按时间顺序写入文件,每行一个条目。每个条目的格式为: [时间戳][空格][用户id][空格][页面类型id]\n 您的任务是从一组日志中确定所有用户中最常见的10个三页序列 例如,下面是一个示例日志: 1248977297 BBBB Search 1248977302 AAAA Browse 1248977308 BBBB Search 1248977310 AAAA Browse 1248977317 BBBB Search 1248977325 AAAA Search 1248

问题是:

条目按时间顺序写入文件,每行一个条目。每个条目的格式为:

[时间戳][空格][用户id][空格][页面类型id]\n

您的任务是从一组日志中确定所有用户中最常见的10个三页序列

例如,下面是一个示例日志:

1248977297 BBBB Search
1248977302 AAAA Browse
1248977308 BBBB Search
1248977310 AAAA Browse
1248977317 BBBB Search
1248977325 AAAA Search
1248977332 AAAA Search
1248977332 BBBB Search
1248977339 BBBB Checkout
1248977348 AAAA Search
1248977352 BBBB Browse
1248977367 AAAA Search



The first three-page sequence made by user AAAA is “Browse->Browse->Search”
The second three-page-sequence made by user AAAA is “Browse->Search->Search” 
The third three-page-sequence made by user AAAA is “Search->Search->Search”
The fourth three-page-sequence made by user AAAA is “Search->Search->Search”
给出示例数据的程序输出应为:

Search -> Search -> Search = 4
Browse -> Browse -> Search = 1
Search -> Search -> Checkout = 1
Browse -> Search -> Search = 1
Search -> Checkout -> Browse = 1
输出必须包含前10个三页序列(按顺序)和每个序列的出现次数

我想到的最好的算法是O(n^2),但我发现答案表明它可以在O(n+n*lg(n))中完成,我如何存档这种复杂性?假设在O(n)中列出并在O(n lg(n))中排序

/*解决方案
*运行时复杂性:O(n^2)。
*空间复杂度:O(n)。
*/
导入java.io.*;
导入java.util.*;
公共类解决方案{
公共静态void main(字符串args[])引发IOException{
/*
*从txt文件读取输入。
*/
String file=“C:\\Users\\Public\\Documents\\txt\\files”;
BufferedReader f=新的BufferedReader(新的文件读取器(file+“.txt”);
字符串行=”;
/*
*@map数据结构以存储所有用户及其页面ID。
*/
Map Map=newhashmap();
/*
*读取txt或日志文件,并将用户访问的所有页面序列存储在@map和列表中。
*/
而((line=f.readLine())!=null和&line.trim().length()!=0){
StringTokenizer令牌=新的StringTokenizer(行);
while(tokens.hasMoreElements()){
字符串timeStamp=tokens.nextToken();
int userId=Integer.parseInt(tokens.nextToken());
字符串pageType=tokens.nextToken();
列表值=map.get(userId);
如果(值==null){
值=新的ArrayList();
map.put(用户ID、值);
}
添加(页面类型);
}
}
/*
*按用户创建序列。
*/
List listSequences=generateSequencesByUser(映射);
/*
*计算每个序列的频率。
*/
Map mapFrequency=countFrequencySequences(列表序列);
/*
*按值对地图进行排序。
*/
Map sortedMap=解决方案。sortByValue(映射频率);
/*
*打印前10个序列。
*/
printTop10(分类地图);
}
/*
*方法按用户创建序列。
*/
公共静态列表按用户生成序列(映射){
列表=新的ArrayList();
对于(Map.Entry:Map.entrySet()){
int key=entry.getKey();
对于(int i=2;i”+entry.getValue().get(i-1)+“->”+entry.getValue().get(i);
列表。添加(seq);
}
}
退货清单;
}
/*
*方法计算每个序列的频率并存储在地图中。
*/
公共静态映射countFrequencySequences(列表序列){
Map mapFrequency=新HashMap();
用于(字符串临时值:listSequences){
整数计数器=mapFrequency.get(温度);
if(计数器==null){
计数器=1;
映射频率输入(温度、计数器);
}否则{
映射频率输入(温度、计数器+1);
}
}
返回频率;
}
/*
*方法打印前10个序列。
*/
公共静态无效打印TOP10(地图){
整数计数=0;
对于(Map.Entry:Map.entrySet()){
计数++;
如果(计数>10){
打破
}否则{
System.out.println(entry.getKey()+“=”+entry.getValue());
}
}
}
/*
*按值对映射进行排序。
*/
公共静态映射sortByValue(映射映射){
List=新的LinkedList(map.entrySet());
Collections.sort(list,newcomparator(){
公共整数比较(对象o1、对象o2){
返回((可比)((Map.Entry)(o2)).getValue()).compareTo((Map.Entry)(o1)).getValue());
}
});
映射结果=新建LinkedHashMap();
for(Iterator it=list.Iterator();it.hasNext();){
Map.Entry=(Map.Entry)it.next();
put(entry.getKey(),entry.getValue());
}
返回结果;
}
}

通过将问题分为三个简单的任务,您可以在O(N LogN)或更好的情况下完成任务:

  • 按时间戳对列表进行排序
  • 对每个三页序列进行计数,以及
  • 按计数选择前十项
  • 第一个任务是标准排序。让我们假设现在是O(N LogN)*

    第二个任务可以通过一对哈希映射轻松完成:

    • 对于每个用户,在第一个哈希映射中保留其最后三个页面的三元素列表。每次发现用户的新操作时,将列表中的页面移动一次
    • 如果上述步骤中的列表有三个条目,则为它们生成一个由三部分组成的键,并在第二个哈希映射中增加其计数
    上面的每个步骤对于每个日志条目都是一个O(1)操作,因此此任务的计时是O(N)

    第三个按计数选择前十个条目的任务可以通过检索键计数对并按计数排序来完成。在最坏的情况下,当所有页面转换都是唯一的时,您将得到3N个要排序的条目,因此此任务再次是O(N LogN)*

    一旦您了解了算法,实现就应该简单明了,因为Java提供了用于实现每个任务的所有构建块
    /* Solution
     * Runtime complexity: O(n^2).
     * Spatial complexity: O(n).
     */
    import java.io.*;
    import java.util.*;
    
    public class Solution {
    
        public static void main(String args[]) throws IOException {
            /*
             * Reads the input from a txt file.
             */
            String file = "C:\\Users\\Public\\Documents\\txt\\files";
            BufferedReader f = new BufferedReader(new FileReader(file + ".txt"));
            String line = "";
    
            /*
             * @map data structure to store all the users with their page ids.
             */
            Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
    
            /*
             *Read the txt or log file and store in the @map the user<Integer> and in a list<String> all the page sequences that he visited.
             */
            while ((line = f.readLine()) != null && line.trim().length() != 0) {
                StringTokenizer tokens = new StringTokenizer(line);
                while (tokens.hasMoreElements()) {
                    String timeStamp = tokens.nextToken();
                    int userId = Integer.parseInt(tokens.nextToken());
                    String pageType = tokens.nextToken();
    
                    List<String> values = map.get(userId);
                    if (values == null) {
                        values = new ArrayList<String>();
                        map.put(userId, values);
                    }
                    values.add(pageType);
                }
            }
            /*
             * Create the sequences by user.
             */
            List<String> listSequences = generateSequencesByUser(map);
    
            /*
             * Count the frequency of each sequence.
             */
            Map<String, Integer> mapFrequency = countFrequencySequences(listSequences);
    
            /*
             * Sort the map by values.
             */
            Map<String, Integer> sortedMap = Solution.sortByValue(mapFrequency);
    
            /*
             * Print the Top 10 of sequences.
             */
            printTop10(sortedMap);
        }
        /*
         * Method to create sequences by user.
         */
        public static List<String> generateSequencesByUser(Map<Integer, List<String>> map) {
            List<String> list = new ArrayList<String>();
            for (Map.Entry<Integer, List<String>> entry : map.entrySet()) {
                int key = entry.getKey();
                for (int i = 2; i < entry.getValue().size(); i++) {
                    String seq = entry.getValue().get(i - 2) + "->" + entry.getValue().get(i - 1) + "->" + entry.getValue().get(i);
                    list.add(seq);
                }
            }
            return list;
        }
    
        /*
         * Method the frequency of each sequence and stored in a map.
         */
        public static Map<String, Integer> countFrequencySequences(List<String> listSequences) {
            Map<String, Integer> mapFrequency = new HashMap<String, Integer>();
    
            for (String temp : listSequences) {
                Integer counter = mapFrequency.get(temp);
                if (counter == null) {
                    counter = 1;
                    mapFrequency.put(temp, counter);
                } else {
                    mapFrequency.put(temp, counter + 1);
                }
            }
            return mapFrequency;
        }
    
        /*
         * Method to print the top 10 of sequences.
         */
        public static void printTop10(Map<String, Integer> map) {
            int count = 0;
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                count++;
                if (count > 10) {
                    break;
                } else {
                    System.out.println(entry.getKey() + " = " + entry.getValue());
                }
            }
        }
    
        /*
         * Order the map by values.
         */
        public static Map<String, Integer> sortByValue(Map<String, Integer> map) {
            List list = new LinkedList(map.entrySet());
            Collections.sort(list, new Comparator() {
                public int compare(Object o1, Object o2) {
                    return ((Comparable) ((Map.Entry) (o2)).getValue()).compareTo(((Map.Entry) (o1)).getValue());
                }
            });
    
            Map result = new LinkedHashMap();
            for (Iterator it = list.iterator(); it.hasNext();) {
                Map.Entry entry = (Map.Entry) it.next();
                result.put(entry.getKey(), entry.getValue());
            }
            return result;
        }
    
    
    }