【百度面经】提前批Java一面|0721

alt alt alt alt alt alt alt alt alt alt alt alt alt alt alt alt alt

import java.io.*;
import java.util.*;
import java.util.Map.Entry;

public class Top10IPs {

    public static void main(String[] args) throws IOException {
        String inputFilePath = "path/to/large/file.txt";
        String tempDirectory = "path/to/temp/directory/";

        // Step 1: Split the large file into smaller chunks
        List<String> chunkFiles = splitFile(inputFilePath, tempDirectory);

        // Step 2: Count IPs in each chunk and save intermediate results
        List<String> resultFiles = new ArrayList<>();
        for (String chunkFile : chunkFiles) {
            String resultFile = countIPsInChunk(chunkFile, tempDirectory);
            resultFiles.add(resultFile);
        }

        // Step 3: Merge intermediate results and find top 10 IPs
        List<Entry<String, Integer>> top10IPs = mergeResults(resultFiles);
        
        // Print the top 10 IPs
        for (Entry<String, Integer> entry : top10IPs) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }

    // Method to split the large file into smaller chunks
    public static List<String> splitFile(String inputFilePath, String tempDirectory) throws IOException {
        List<String> chunkFiles = new ArrayList<>();
        int chunkSize = 1000000; // Adjust the chunk size as needed
        int chunkIndex = 0;
        
        BufferedReader reader = new BufferedReader(new FileReader(inputFilePath));
        String line;
        while ((line = reader.readLine()) != null) {
            String chunkFilePath = tempDirectory + "chunk_" + chunkIndex + ".txt";
            PrintWriter writer = new PrintWriter(new FileWriter(chunkFilePath, true));
            int lineCount = 0;
            while (lineCount < chunkSize && line != null) {
                writer.println(line);
                line = reader.readLine();
                lineCount++;
            }
            writer.close();
            chunkFiles.add(chunkFilePath);
            chunkIndex++;
        }
        reader.close();
        return chunkFiles;
    }

    // Method to count IPs in each chunk and save intermediate results
    public static String countIPsInChunk(String chunkFilePath, String tempDirectory) throws IOException {
        Map<String, Integer> ipCountMap = new HashMap<>();
        
        BufferedReader reader = new BufferedReader(new FileReader(chunkFilePath));
        String line;
        while ((line = reader.readLine()) != null) {
            ipCountMap.put(line, ipCountMap.getOrDefault(line, 0) + 1);
        }
        reader.close();

        String resultFilePath = tempDirectory + "result_" + chunkFilePath.substring(chunkFilePath.lastIndexOf('_') + 1);
        PrintWriter writer = new PrintWriter(new FileWriter(resultFilePath));
        for (Entry<String, Integer> entry : ipCountMap.entrySet()) {
            writer.println(entry.getKey() + "," + entry.getValue());
        }
        writer.close();
        return resultFilePath;
    }

    // Method to merge intermediate results and find top 10 IPs
    public static List<Entry<String, Integer>> mergeResults(List<String> resultFiles) throws IOException {
        Map<String, Integer> ipCountMap = new HashMap<>();
        
        for (String resultFile : resultFiles) {
            BufferedReader reader = new BufferedReader(new FileReader(resultFile));
            String line;
            while ((line = reader.readLine()) != null) {
                String[] parts = line.split(",");
                String ip = parts[0];
                int count = Integer.parseInt(parts[1]);
                ipCountMap.put(ip, ipCountMap.getOrDefault(ip, 0) + count);
            }
            reader.close();
        }

        // Find the top 10 IPs
        PriorityQueue<Entry<String, Integer>> minHeap = new PriorityQueue<>(Map.Entry.comparingByValue());
        for (Entry<String, Integer> entry : ipCountMap.entrySet()) {
            minHeap.offer(entry);
            if (minHeap.size() > 10) {
                minHeap.poll();
            }
        }
        
        List<Entry<String, Integer>> top10IPs = new ArrayList<>(minHeap);
        top10IPs.sort((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue()));
        return top10IPs;
    }
}

代码说明

  1. splitFile方法:将大文件分割成多个较小的文件,每个文件包含一定数量的IP地址。
  2. countIPsInChunk方法:统计每个小文件中的IP访问次数,并将结果保存到一个中间结果文件中。
  3. mergeResults方法:合并所有中间结果文件,并找出访问次数排名前十的IP地址。

这段代码假设已经根据具体需求调整了块大小和文件路径。此方法有效地处理了大文件,并找出了访问次数最多的前十个IP地址。

注意事项

  • 内存管理:在处理过程中要密切注意内存的使用情况,以避免内存溢出。
  • 磁盘I/O:优化磁盘I/O操作可以显著提高处理效率。
  • 数据一致性:在处理大文件时,要确保数据的完整性和一致性。
  • 错误处理:添加适当的错误处理逻辑以应对文件读取、写入或排序过程中可能出现的异常情况。

通过上述方法,我们可以在不耗尽机器内存的情况下,有效地处理大文件并找出访问次数排名前十的IP地址。

15. 算法题:在长度为N的有序数组中快速查找所有值为M的元素下标(M可能重复出现)

要在长度为N的有序数组中快速查找所有值为M的元素下标,可以使用二分查找来找到值为M的第一个和最后一个位置,然后再遍历这些位置之间的元素获取所有的下标。这种方法的时间复杂度是O(log N) + O(k),其中k是值为M的元素的数量。

下面是一个Java实现:

import java.util.ArrayList;
import java.util.List;

public class FindIndices {

    public static void main(String[] args) {
        int[] nums = {1, 2, 2, 2, 3, 4, 5};
        int target = 2;
        List<Integer> indices = findAllIndices(nums, target);
        System.out.println(indices);  // 输出:[1, 2, 3]
    }

    public static List<Integer> findAllIndices(int[] nums, int target) {
        List<Integer> indices = new ArrayList<>();
        
        // 辅助方法,找到target的第一个和最后一个位置
        int firstIndex = findFirst(nums, target);
        int lastIndex = findLast(nums, target);

        // 如果找到的第一个位置是-1,说明数组中没有target
        if (firstIndex == -1) {
            return indices;
        }

        // 遍历从firstIndex到lastIndex的范围,添加所有位置到结果列表中
        for (int i = firstIndex; i <= lastIndex; i++) {
            indices.add(i);
        }

        return indices;
    }

    // 辅助方法,找到target的第一个位置
    private static int findFirst(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int result = -1;

        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                result = mid;
                right = mid - 1;  // 继续在左边搜索
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return result;
    }

    // 辅助方法,找到target的最后一个位置
    private static int findLast(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int result = -1;

        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                result = mid;
                left = mid + 1;  // 继续在右边搜索
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return result;
    }
}

代码说明

  1. findAllIndices方法用于找到所有值为target的元素的下标。
  2. findFirst方法用于找到target在数组中的第一个位置。
  3. findLast方法用于找到target在数组中的最后一个位置。
  4. 如果找到的第一个位置是-1,说明数组中没有target,直接返回空列表。
  5. 否则,遍历从firstIndexlastIndex的范围,将所有的下标添加到结果列表中。

面经原帖有三毛六站神发布,答案由程序员Hasity整理。

alt

#软件开发笔面经#
校招面经大全 文章被收录于专栏

收录各个网友分享的各个公司的面经,并给出答案。

全部评论
杜绝白嫖,文章末尾送朵小花花吧。更好的阅读体验:https://app6721.acapp.acwing.com.cn/interview/27
4 回复 分享
发布于 07-23 11:23 北京
大佬太强了
2 回复 分享
发布于 07-23 21:02 广东
点赞 回复 分享
发布于 07-22 15:10 上海
太强了佬!
点赞 回复 分享
发布于 07-22 16:17 北京
点赞 回复 分享
发布于 07-23 19:11 四川
大佬太强了
点赞 回复 分享
发布于 07-24 19:32 香港
大佬啊
点赞 回复 分享
发布于 07-26 10:47 北京

相关推荐

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不知道这个系列可以更新多久,我预期是希望逐步整理所有的我认为有价值的问题,趁着还有时间,多复盘一下,大概每篇更新四五个问题,在精不在多。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果大家觉得有用欢迎点赞收藏送花!1.(Minimax二面)react的单向数据流怎么理解,有什么好处?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当时对这个概念了解的不太深入,没回答好,下来复盘我觉得可以按照如下思路展开。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;首先这个问题想回答好就需要理解几个概念:什么是数据流?什么是单向?为什么要设置成单向的?咱一个一个看看&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;react组件中最常用到的数据有两类:state和props,state是组件内部自行维护的,props是父组件传给子组件的,下面说的数据我理解都指的是props。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据流:也就是数据在不同组件或节点之间的流动,比如a数据(引用类型)被b节点引用,又被b传递给c,那么a数据改变后会影响b,从而影响c,这就叫数据流。但是这种流动是双向的,因为如果在b或c修改了这个数据,其他的也会变化。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;单向:在react中,单向是”自顶向下“的,也就是react规定了数据的流向是从外层组件向内层组件进行传递和更新的,而内层组件是无法直接修改props影响外层的。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;那么为什么要用单向的形式?如果内层的组件可以通过修改props来修改外层的数据,那么外层使用到这个数据或者其他使用到这个数据的地方都会造成数据更新,UI渲染也会改变,这会造成数据紊乱和不可控。所以为了更好的可控性,react设计了单向数据流。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;除此之外还有一个好处,所有的数据更新是单向的,那么出现问题的时候会更好溯源,因为修改数据的链路是确定的,排查起来顺着调用链就可以一层一层找到问题了。2.(快手二面)如果用户传了一个很大的excel要解析,如何处理比较好?web&nbsp;worker如何和主线程通信?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;首先这个问题可以泛化到很多复杂计算上,而不只是excel解析,其次可以延申展开一些东西。‘&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;web&nbsp;worker是JS里难得的多线程。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在&nbsp;HTML5&nbsp;中,工作线程的出现使得在&nbsp;Web&nbsp;页面中进行多线程编程成为可能。众所周知,传统页面中(HTML5&nbsp;之前)的&nbsp;JavaScript&nbsp;的运行都是以单线程的方式工作的,虽然有多种方式实现了对多线程的模拟(例如:JavaScript&nbsp;中的&nbsp;setinterval&nbsp;方法,setTimeout&nbsp;方法等),但是在本质上程序的运行仍然是由&nbsp;JavaScript&nbsp;引擎以单线程调度的方式进行的。在&nbsp;HTML5&nbsp;中引入的工作线程使得浏览器端的&nbsp;JavaScript&nbsp;引擎可以并发地执行&nbsp;JavaScript&nbsp;代码,从而实现了对浏览器端多线程编程的良好支持。HTML5&nbsp;中的&nbsp;Web&nbsp;Worker&nbsp;可以分为两种不同线程类型,一个是专用线程&nbsp;Dedicated&nbsp;Worker,一个是共享线程&nbsp;Shared&nbsp;Worker。两种类型的线程各有不同的用途&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;和主线程之间的通信是通过postMessage来进行的。简单的说,主线程用postMessage向webworker推送消息,子线程用onMessage接受并处理,处理完之后在子线程内调用postMessage将结果返回给主线程,主线程同样用onMessage接受。具体内容请查阅MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers3.(灵犀互娱一面)多个web&nbsp;worker如何保证顺序?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;还好当时面试官只是提了一嘴,没让我解答。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这个问题属于上面的问题的延申版本,其实没了解过具体方式也能猜个七七八八(类比文件切片上传之类的)。要想保证顺序,最简单的方式就是在给不同web&nbsp;worker分配任务时附带上一个唯一编号,在web&nbsp;worker处理完返回结果时也将这个编号一起发回给主线程,在主线程中按顺序重组。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;查了一下,webworker自身也提供了all和race等方法,这些其实就是在promise的基础上封装的(想来也正常,毕竟不同线程,肯定要异步返回)。有一个很详细的知乎文章,有兴趣的uu们自行查阅哈:https://zhuanlan.zhihu.com/p/41431253#:~:text=web-worker4.(快手二面)setInterval准确吗?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;感觉大家可能也看过,但是这个问题还是比较有意思的。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;答案是不准确,为啥呢?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;嵌套的&nbsp;setTimeout&nbsp;相较于&nbsp;setInterval&nbsp;能够更精确地设置两次执行之间的延时。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面来比较这两个代码片段。第一个使用的是&nbsp;setInterval:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;i&nbsp;=&nbsp;1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setInterval(function()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;func(i++);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;100);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第二个使用的是嵌套的&nbsp;setTimeout:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;i&nbsp;=&nbsp;1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setTimeout(function&nbsp;run()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;func(i++);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setTimeout(run,&nbsp;100);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;100);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对&nbsp;setInterval&nbsp;而言,内部的调度程序会每间隔&nbsp;100&nbsp;毫秒执行一次&nbsp;func(i++)(图1),时间开始计算的位置是调用内部方法的那一刻,因此第一次方法结束到第二次开始之间的时间间隔其实是小于100ms的,这就是为啥他不准确。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;再看看setTimeout(图2)。时间开始计算的位置是内部方法调用结束的时刻,也就是说两次方法之间的时间间隔是准确的100ms。好处在于如果内部方法调用的耗时比较长,那么这个方法也能确保两次调用之间的时间间隔。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;延申:如果setInterval的内部函数执行耗时大于设定的时间间隔咋办?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在这种情况下,JavaScript&nbsp;引擎会等待&nbsp;func&nbsp;执行完成,然后检查调度程序,如果时间到了,则&nbsp;立即&nbsp;再次执行它。极端情况下,如果函数每次执行时间都超过&nbsp;delay&nbsp;设置的时间,那么每次调用之间将完全没有停顿。5.(百度一面)语义化标签如果没加样式,跟div、span这些非语义化标签有啥区别?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这个就看大家对语义化标签的理解了。首先肯定能想到的一点就是更方便理解,看到header就知道是顶,看到aside就知道是侧边栏,但是这些任务div都能完成,区别在哪?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.即使在没有CSS的情况下,HTML页面也能呈现出很好地内容结构、代码结构。语义标签具有默认的CSS,比如html5之前的h1、h2等等就是语义化标签,他们表示几级标题;虽然我们在html没有引入任何css时,我们仍然可以看到h标签有字体放大加粗的效果。&nbsp;实际上,html本身是没有表现的,我们看到例如&nbsp;h1标签是粗体,字体大小2em,加粗;strong是加粗的,不要认为这是html的表现,这些其实html默认的css样式在起作用,所以去掉或样式丢失的时候能让页面呈现清晰的结构不是语义化的HTML结构的优点,但是浏览器都有有默认样式,默认样式的目的也是为了更好的表达html的语义,可以说浏览器的默认样式和语义化的HTML结构是不可分割的&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.不仅人更容易看懂,也更利于机器看懂,对SEO更友好。再次感谢大家的点赞收藏和花花#软件开发2024笔面经##前端##快手##minimax##百度##面经#
点赞 评论 收藏
分享
63 198 评论
分享
牛客网
牛客企业服务