首页 > 编程语言 >焦点科技编程挑战赛2022题解

焦点科技编程挑战赛2022题解

时间:2022-11-15 17:14:03浏览次数:43  
标签:origin hashMap int 题解 dest 2022 挑战赛 new line

比赛说明:

比赛在四个学校开展,南理南航南农和矿大。

题目

查找文本差异

要求

  • origindest中分别包含1000w+条数据
  • dest对数据进行了打乱操作,即origindest中相同数据行的顺序不相同
  • 程序运行的总内存消耗不能超过30MB
  • 程序运行的总时间消耗不能超过10分钟
  • origin中存在但dest中不存在的数据,取origin中的行号;dest中存在但origin中不存在的数据,取dest中的行号
  • 输出的行号数组按照升序排列

判定规则

  • 总内存消耗超过30MB,判定为不合格
  • 总时间消耗超过10分钟,判定为不合格

示例

假设 origin 文件内容为:

e630f353-01b3-4b2c-989c-6236b476140a
cc8626ef-c45b-4b9a-96b6-3206d8adc518
8c622fb7-8150-4487-91f2-6a860eb14feb
78c0fe67-b0ea-4fe5-9ef0-4157d956e3d2

假设 dest 文件内容为:

78c0fe67-b0ea-4fe5-9ef0-4157d956e3d2
14fbf539-a614-402c-8ab9-8e7438f3bd72
e630f353-01b3-4b2c-989c-6236b476140a
cc8626ef-c45b-4b9a-96b6-3206d8adc518

输出结果为:

[1, 2]

解决方案:

先分析本题的数据量。本题文件数据量两个文件大约在3000万条左右,比较符合海量数据的处理。同时对时间和内存的限定也十分的苛刻。

所以本题采用的方法是将大文件每行按hash值放入对应的小文件中,然后依次处理每个小文件。

步骤:

首先将两个大文件按hash值分别放入切割后的小文件,两个文件一共800mb,2800w行左右

  while ((destLine=dest.readLine())!=null){
                   int code = hash(destLine)%200;
                   if (code<0)code=-code;//取绝对值
                   /**
                    * 追加文件需要在FileWriter第二个参数选择true
                    */
                   BufferedWriter out = new BufferedWriter(new FileWriter("src/main/resources/file/"+code+".txt",true));
                   out.write(destLine);
                   out.write(","+String.valueOf(count));  //添加逗号是为了将行号加入,减少后面再去寻找行号的时间
                   out.write("\n");
                   out.flush();
                    count++;
               }
   while ((originLie=origin.readLine())!=null){

                    int code = hash(originLie)%200;
                    if (code<0)code=-code;//取绝对值
                    /**
                     * 追加文件需要在FileWriter第二个参数选择true
                     */
                    BufferedWriter out = new BufferedWriter(new FileWriter("src/main/resources/file/"+code+".txt",true));
                    out.write(originLie);
                    out.write(","+count);
                    out.write("\n");
                    out.flush();
                    count++;
                }
//写入第一个文件花费 16000ms
//写入两个大概33000ms

然后分别遍历这些小文件中的数据

  							 String line=null;
               List<String> list = new ArrayList<>();
               for (int i=0;i<200;i++){
                   HashMap<String,String> hashMap = new HashMap<>();
                   BufferedReader bufferedReader = new BufferedReader(new FileReader("src/main/resources/file/"+i+".txt"));
                  while( (line = bufferedReader.readLine())!=null){
                    String[] a = line.split(",");
                    line = a[0];
                    String num = a[1];
                    //若HashMap中没有字符串,则将字符串和行号放入
                    //若后续出现重复,则将行号改为true
                      if (hashMap.containsKey(line)){     
                          hashMap.replace(line,"true");
                      }
                      else {   
                          hashMap.put(line,num);
                      }

                  }
                   Set<String> Key = hashMap.keySet();
                 //向list中添加行号
                   for (String key:Key){
                       if (!hashMap.get(key).equals("true")){
                           list.add(hashMap.get(key));
                       }
                   }
                   hashMap=null; //置空 等GC

               }

然后便是将list转化为int类型数组输出

  int [] result = new int[list.size()];
               int index =0;
               for (int i=0;i<list.size();i++){
                   String num = list.get(i);
                   result[index++] = Integer.parseInt(num);
               }

处理结果:

时间花费6分钟

至此内存与时间的限制都满足了。

注意问题

hashMap内存的释放

全部代码:

package com.focustech.fpc.algorithm;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Stream;

import static java.util.Objects.hash;

/**
 * 差异分析器实现类示例
 * @author KeCheng
 **/
public class DemoDifferenceAnalyser implements IDifferenceAnalyser{


    @Override
    public int[] diff() {
        /**
         * 将大文件分割成多份小文件
         * 使用hashSet进行查看是否含有
         * 用流来读取文件
         * 难点在于在规定时间内使用规定内存
         * 用hashSet可以节省时间
         */

           try {
               ArrayList<Integer> res = new ArrayList<>();
               int cnt = 0;

               File file=new File("src/main/resources/dest");
              String fileDestName=file.getName();
              long fileDestSize=file.length();

              File file1 = new File("src/main/resources/origin");
              String fileOriginName = file1.getName();
              long fileOriginSize = file1.length();


               //缓冲流 =================================================
               InputStream inputDest = this.getClass().getClassLoader().getResourceAsStream("dest");
               InputStreamReader destReader= new InputStreamReader(inputDest);
               BufferedReader dest = new BufferedReader(destReader);

               InputStream inputOrigin = this.getClass().getClassLoader().getResourceAsStream("origin");
               InputStreamReader originReader= new InputStreamReader(inputOrigin);
               BufferedReader origin = new BufferedReader(originReader);

               //========================================================
               /**
                * 分割文件 两个大文件分割成400份小文件
                * 本次操作为创建400个文件
                */
               for(int i=0;i<200;i++){
                   File file2 = new File("src/main/resources/file/"+i+".txt");
                   if (file2.exists()) file2.delete();
                   if (!file2.exists()) file2.createNewFile();
               }
               String destLine,originLie;
               /*
               根据哈希值将文件中的行数放到400个文件中,
                哈希值相同的会被放到一个文件里
               */
               long timeStart1 = System.currentTimeMillis();
                int count = 0;
               while ((destLine=dest.readLine())!=null){
                   int code = hash(destLine)%200;
                   if (code<0)code=-code;//取绝对值
                   /**
                    * 追加文件需要在FileWriter第二个参数选择true
                    */
                   BufferedWriter out = new BufferedWriter(new FileWriter("src/main/resources/file/"+code+".txt",true));
                   out.write(destLine);
                   out.write(","+String.valueOf(count));
                   out.write("\n");
                   out.flush();
                    count++;
               }
               System.out.println("第一次写文件需要花费:");
               System.out.println(System.currentTimeMillis()-timeStart1);

               long timeStart2 = System.currentTimeMillis();
            count = 0;
                while ((originLie=origin.readLine())!=null){

                    int code = hash(originLie)%200;
                    if (code<0)code=-code;//取绝对值
                    /**
                     * 追加文件需要在FileWriter第二个参数选择true
                     */
                    BufferedWriter out = new BufferedWriter(new FileWriter("src/main/resources/file/"+code+".txt",true));
                    out.write(originLie);
                    out.write(","+count);
                    out.write("\n");
                    out.flush();
                    count++;
                }
               /**
                * 读写操作约耗时5min
                */
               System.out.println("第二次写文件需要花费");
               System.out.println(System.currentTimeMillis()-timeStart2);

               /**
                * 接下来遍历200个文件
                */

               String line=null;
               List<String> list = new ArrayList<>();
//               HashMap<String,String> numMap = new HashMap<>();
               for (int i=0;i<200;i++){
                   HashMap<String,String> hashMap = new HashMap<>();
                   BufferedReader bufferedReader = new BufferedReader(new FileReader("src/main/resources/file/"+i+".txt"));
                  while( (line = bufferedReader.readLine())!=null){
                    String[] a = line.split(",");
                    line = a[0];
                    String num = a[1];
                      if (hashMap.containsKey(line)){
                          hashMap.replace(line,"true");
                      }
                      else {
                          hashMap.put(line,num);
                      }

                  }
                   Set<String> Key = hashMap.keySet();
                   for (String key:Key){
                       if (!hashMap.get(key).equals("true")){
                           list.add(hashMap.get(key));
                       }
                   }
                   hashMap=null; //置空 等GC

               }
               dest.close();
               origin.close();
               int [] result = new int[list.size()];
               int index =0;
               for (int i=0;i<list.size();i++){
                   String num = list.get(i);
                   result[index++] = Integer.parseInt(num);
               }
             Arrays.sort(result);
               System.out.println(result);
              return  result;
              
           } catch (IOException ex) {
               ex.printStackTrace();
           }
        return new int[0];
    }
    }



标签:origin,hashMap,int,题解,dest,2022,挑战赛,new,line
From: https://www.cnblogs.com/cc-coding/p/16893042.html

相关文章

  • 报告分享|2022年直播行业研究最新动态
    报告全文链接:http://tecdat.cn/?p=30326中国直播电商起源于2016年,之后大致经历2017-2018年的快速拓展期、2019-2020年的百花齐放期以及2021至今的全民直播三大阶段。中国......
  • CF1598F RBS 题解
    题意给\(n\)个串,求将这\(n\)个串以任意顺序接起来的最大的是合法括号序列的前缀数。分析\(n\)很小,考虑状压dp。有一个很典的转化是将(看成\(+1\),将)看成\(-......
  • 20221115_T4B_折半搜索双指针
    题意市面上共有\(n\)张门票,方便起见,我们把它们从\(1\)至\(n\)编号。其中,\(i\)号门票对应的场次为第\(b_i,1\leqb_i\leqk)\)场,价格为\(c_i\)元,且座位的排数为......
  • test20221115 打铁记
    总述\(53+20+20+0=93\),班上\(rk9\),太菜了。考场T1特殊性质+暴力(可是没有打满),T2特殊性质,T3暴力。费时\(40\)分钟,剩下的时间写正解(没写出来)+摆烂。感谢cy同志让......
  • 20221115_T3A+_贪心二分
    题意你在和Yazid做游戏。Yazid给了你一棵\(n\)个节点的树,并让你删除这棵树上的恰好\(k\)条边,使得整棵树被分成\(k+1\)个连通块。你觉得太简单了,随便删k条边......
  • 20221114
    存疑的点分类阈值是否和常识一样为0.5/如果改成不是奇偶数判断(例如是否被3整除)阈值是否是0.5BATCH_SIZE:即一次训练所抓取的数据样本数量,更改之后有什么影响,built_......
  • 2022 China Collegiate Programming Contest (CCPC) Guangzhou Onsite I
    I.Infectionn=2000,我们考虑dp我们转化题意发现就是找一个连通子块然后连通块的权重就是其中任何一个点的a[i]其他都是p[i]但是对于连通块相接的点我们都要让他是(1-......
  • ACR2022的辩论:DMARDs在pre-RA中的作用
    ACR2022的辩论:DMARDs在pre-RA中的作用2022年11月13日 亚临床RA在风湿病学实践中越来越常见;然而,目前尚不清楚如何管理这些患者,以及启动DMARD是否可以预防RA的发展。 ......
  • 云原生周刊 | 百家争鸣的边缘计算时代即将到来?| 2022-11-14
    今年的KubeCon大会有一个很奇怪的现象,到场的几乎都是小公司,没有大公司。可能是因为这些大公司恰好在这个时候都有自己的活动要举办,也有可能是他们正在快马加鞭研发他们的......
  • 2022-11-15 如何给rich-text里的标签添加类名
    e.title=e.title.replace(/\<p/gi,'<pstyle="display:inline-block!important"');我这个是遍历一个数组中的所有title,并且给每个title的值都替换掉指定的标签,需要......