Meta PE SDE Coding Round 面试经验分享:回文判断和数据分析算法题 - Oavoservice

🎤 Meta PE SDE 0617 Coding Round 面经
👩💻 Candidate 在 Meta PE SDE Coding Round 面试中遇到了两个经典的算法题。
Pe的面经,烙印面试官上来就要求写Java,整体面试体验还不错!
💻 Coding 1: 回文判断
题目:判断 string 是不是 palindrome
📝 题目要求
- 需要 ignore lower/upper 的 case
- 比较的时候 skip 掉标点符号
- 只考虑字母和数字字符
- 使用双指针算法
❓ 问题分析
这是一个经典的回文判断问题:
- 核心思想:双指针从两端向中间移动
- 关键点:字符预处理和边界条件
- 优化:可以原地处理,不需要额外空间
💡 思路设计
使用双指针方法:
- 左指针从字符串开头开始
- 右指针从字符串末尾开始
- 跳过非字母数字字符
- 比较字符(忽略大小写)
- 向中间移动指针
💻 代码实现
public class PalindromeChecker {
// 方法1:双指针 - 最优解
public boolean isPalindrome(String s) {
if (s == null || s.length() == 0) {
return true;
}
int left = 0;
int right = s.length() - 1;
while (left < right) {
// 跳过非字母数字字符
while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
left++;
}
while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
right--;
}
// 比较字符(忽略大小写)
if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {
return false;
}
left++;
right--;
}
return true;
}
// 方法2:预处理字符串
public boolean isPalindromePreprocess(String s) {
if (s == null || s.length() == 0) {
return true;
}
// 预处理:只保留字母数字字符并转为小写
StringBuilder cleaned = new StringBuilder();
for (char c : s.toCharArray()) {
if (Character.isLetterOrDigit(c)) {
cleaned.append(Character.toLowerCase(c));
}
}
String cleanedStr = cleaned.toString();
int left = 0;
int right = cleanedStr.length() - 1;
while (left < right) {
if (cleanedStr.charAt(left) != cleanedStr.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
// 方法3:递归解法
public boolean isPalindromeRecursive(String s) {
if (s == null || s.length() == 0) {
return true;
}
return isPalindromeHelper(s, 0, s.length() - 1);
}
private boolean isPalindromeHelper(String s, int left, int right) {
if (left >= right) {
return true;
}
// 跳过非字母数字字符
while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
left++;
}
while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
right--;
}
// 比较字符
if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {
return false;
}
return isPalindromeHelper(s, left + 1, right - 1);
}
// 测试方法
public static void main(String[] args) {
PalindromeChecker checker = new PalindromeChecker();
// 测试用例1:基本回文
String test1 = "A man, a plan, a canal: Panama";
System.out.println("测试1: " + checker.isPalindrome(test1)); // true
// 测试用例2:非回文
String test2 = "race a car";
System.out.println("测试2: " + checker.isPalindrome(test2)); // false
// 测试用例3:空字符串
String test3 = "";
System.out.println("测试3: " + checker.isPalindrome(test3)); // true
// 测试用例4:单个字符
String test4 = "a";
System.out.println("测试4: " + checker.isPalindrome(test4)); // true
// 测试用例5:只有标点符号
String test5 = ".,";
System.out.println("测试5: " + checker.isPalindrome(test5)); // true
// 测试用例6:数字回文
String test6 = "12321";
System.out.println("测试6: " + checker.isPalindrome(test6)); // true
}
}
🔍 算法分析
- 时间复杂度:O(n),其中n是字符串长度
- 空间复杂度:O(1)(双指针方法)或O(n)(预处理方法)
- 核心思想:双指针 + 字符过滤
✨ 面试官反馈
面试官对双指针解法很满意:"Great! Two pointer approach is optimal. You've handled the edge cases well."
💻 Coding 2: 数据分析
题目:Data Analysis - 恐龙数据分析
📝 题目要求
- 接收两个CSV文件
- 两个文件都有恐龙的meta data
- 按照速度打印恐龙,需要降序排列
- 涉及文件IO操作
❓ 问题分析
这是一个典型的文件IO和数据处理问题:
- 核心思想:读取CSV文件,解析数据,排序输出
- 关键点:CSV解析和排序算法
- 挑战:处理文件格式和数据类型转换
💡 思路设计
使用Java文件IO和集合排序:
- 定义恐龙数据模型
- 读取CSV文件
- 解析每行数据
- 合并两个文件的数据
- 按速度降序排序
- 输出结果
💻 代码实现
import java.io.*;
import java.util.*;
public class DinosaurDataAnalyzer {
// 恐龙数据模型
static class Dinosaur {
String name;
double speed; // km/h
String period;
String diet;
public Dinosaur(String name, double speed, String period, String diet) {
this.name = name;
this.speed = speed;
this.period = period;
this.diet = diet;
}
@Override
public String toString() {
return String.format("%s: %.1f km/h (%s, %s)", name, speed, period, diet);
}
}
// 主方法:分析恐龙数据
public void analyzeDinosaurData(String file1Path, String file2Path) {
List<Dinosaur> dinosaurs = new ArrayList<>();
try {
// 读取第一个CSV文件
readCSVFile(file1Path, dinosaurs);
// 读取第二个CSV文件
readCSVFile(file2Path, dinosaurs);
// 按速度降序排序
dinosaurs.sort((d1, d2) -> Double.compare(d2.speed, d1.speed));
// 输出结果
printResults(dinosaurs);
} catch (IOException e) {
System.err.println("Error reading files: " + e.getMessage());
}
}
// 读取CSV文件
private void readCSVFile(String filePath, List<Dinosaur> dinosaurs) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
boolean isFirstLine = true;
while ((line = reader.readLine()) != null) {
// 跳过标题行
if (isFirstLine) {
isFirstLine = false;
continue;
}
// 解析CSV行
Dinosaur dinosaur = parseCSVLine(line);
if (dinosaur != null) {
dinosaurs.add(dinosaur);
}
}
}
}
// 解析CSV行
private Dinosaur parseCSVLine(String line) {
try {
// 简单的CSV解析(假设没有逗号在引号内的情况)
String[] fields = line.split(",");
if (fields.length >= 4) {
String name = fields[0].trim();
double speed = Double.parseDouble(fields[1].trim());
String period = fields[2].trim();
String diet = fields[3].trim();
return new Dinosaur(name, speed, period, diet);
}
} catch (NumberFormatException e) {
System.err.println("Error parsing line: " + line);
}
return null;
}
// 输出结果
private void printResults(List<Dinosaur> dinosaurs) {
System.out.println("恐龙速度排行榜(降序):");
System.out.println("================================");
for (int i = 0; i < dinosaurs.size(); i++) {
System.out.printf("%d. %s%n", i + 1, dinosaurs.get(i));
}
System.out.println("================================");
System.out.printf("总共分析了 %d 只恐龙%n", dinosaurs.size());
}
// 高级版本:支持更复杂的CSV解析
public void analyzeDinosaurDataAdvanced(String file1Path, String file2Path) {
List<Dinosaur> dinosaurs = new ArrayList<>();
try {
// 读取并合并数据
readCSVFileAdvanced(file1Path, dinosaurs);
readCSVFileAdvanced(file2Path, dinosaurs);
// 去重(基于名称)
removeDuplicates(dinosaurs);
// 按速度降序排序
dinosaurs.sort((d1, d2) -> Double.compare(d2.speed, d1.speed));
// 输出详细统计
printAdvancedResults(dinosaurs);
} catch (IOException e) {
System.err.println("Error reading files: " + e.getMessage());
}
}
// 高级CSV解析(处理引号内的逗号)
private void readCSVFileAdvanced(String filePath, List<Dinosaur> dinosaurs) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
boolean isFirstLine = true;
while ((line = reader.readLine()) != null) {
if (isFirstLine) {
isFirstLine = false;
continue;
}
Dinosaur dinosaur = parseCSVLineAdvanced(line);
if (dinosaur != null) {
dinosaurs.add(dinosaur);
}
}
}
}
// 高级CSV行解析
private Dinosaur parseCSVLineAdvanced(String line) {
try {
List<String> fields = parseCSVFields(line);
if (fields.size() >= 4) {
String name = fields.get(0).trim();
double speed = Double.parseDouble(fields.get(1).trim());
String period = fields.get(2).trim();
String diet = fields.get(3).trim();
return new Dinosaur(name, speed, period, diet);
}
} catch (NumberFormatException e) {
System.err.println("Error parsing line: " + line);
}
return null;
}
// 解析CSV字段(处理引号)
private List<String> parseCSVFields(String line) {
List<String> fields = new ArrayList<>();
StringBuilder currentField = new StringBuilder();
boolean inQuotes = false;
for (int i = 0; i < line.length(); i++) {
char c = line.charAt(i);
if (c == '"') {
inQuotes = !inQuotes;
} else if (c == ',' && !inQuotes) {
fields.add(currentField.toString());
currentField = new StringBuilder();
} else {
currentField.append(c);
}
}
fields.add(currentField.toString());
return fields;
}
// 去重
private void removeDuplicates(List<Dinosaur> dinosaurs) {
Map<String, Dinosaur> uniqueDinosaurs = new LinkedHashMap<>();
for (Dinosaur dinosaur : dinosaurs) {
String key = dinosaur.name.toLowerCase();
if (!uniqueDinosaurs.containsKey(key)) {
uniqueDinosaurs.put(key, dinosaur);
}
}
dinosaurs.clear();
dinosaurs.addAll(uniqueDinosaurs.values());
}
// 输出高级结果
private void printAdvancedResults(List<Dinosaur> dinosaurs) {
System.out.println("恐龙速度详细分析报告");
System.out.println("================================");
// 速度统计
double maxSpeed = dinosaurs.get(0).speed;
double minSpeed = dinosaurs.get(dinosaurs.size() - 1).speed;
double avgSpeed = dinosaurs.stream().mapToDouble(d -> d.speed).average().orElse(0);
System.out.printf("最高速度: %.1f km/h%n", maxSpeed);
System.out.printf("最低速度: %.1f km/h%n", minSpeed);
System.out.printf("平均速度: %.1f km/h%n", avgSpeed);
System.out.println();
// 排行榜
System.out.println("速度排行榜(前10名):");
for (int i = 0; i < Math.min(10, dinosaurs.size()); i++) {
System.out.printf("%d. %s%n", i + 1, dinosaurs.get(i));
}
System.out.println("================================");
}
// 测试方法
public static void main(String[] args) {
DinosaurDataAnalyzer analyzer = new DinosaurDataAnalyzer();
// 创建测试CSV文件
createTestCSVFiles();
// 分析数据
analyzer.analyzeDinosaurData("dinosaurs1.csv", "dinosaurs2.csv");
System.out.println("\n" + "=".repeat(50) + "\n");
// 高级分析
analyzer.analyzeDinosaurDataAdvanced("dinosaurs1.csv", "dinosaurs2.csv");
}
// 创建测试CSV文件
private static void createTestCSVFiles() {
try {
// 创建第一个CSV文件
try (PrintWriter writer = new PrintWriter("dinosaurs1.csv")) {
writer.println("Name,Speed,Period,Diet");
writer.println("Tyrannosaurus Rex,40,Cretaceous,Carnivore");
writer.println("Velociraptor,60,Cretaceous,Carnivore");
writer.println("Triceratops,25,Cretaceous,Herbivore");
}
// 创建第二个CSV文件
try (PrintWriter writer = new PrintWriter("dinosaurs2.csv")) {
writer.println("Name,Speed,Period,Diet");
writer.println("Allosaurus,35,Jurassic,Carnivore");
writer.println("Stegosaurus,15,Jurassic,Herbivore");
writer.println("Brachiosaurus,20,Jurassic,Herbivore");
}
} catch (IOException e) {
System.err.println("Error creating test files: " + e.getMessage());
}
}
}
🔍 算法分析
- 时间复杂度:O(n log n),其中n是恐龙数量(排序占主导)
- 空间复杂度:O(n),存储恐龙数据
- 核心思想:文件IO + 数据解析 + 排序算法
📊 测试用例
// 测试CSV文件1 (dinosaurs1.csv)
Name,Speed,Period,Diet
Tyrannosaurus Rex,40,Cretaceous,Carnivore
Velociraptor,60,Cretaceous,Carnivore
Triceratops,25,Cretaceous,Herbivore
// 测试CSV文件2 (dinosaurs2.csv)
Name,Speed,Period,Diet
Allosaurus,35,Jurassic,Carnivore
Stegosaurus,15,Jurassic,Herbivore
Brachiosaurus,20,Jurassic,Herbivore
// 期望输出(按速度降序):
1. Velociraptor: 60.0 km/h (Cretaceous, Carnivore)
2. Tyrannosaurus Rex: 40.0 km/h (Cretaceous, Carnivore)
3. Allosaurus: 35.0 km/h (Jurassic, Carnivore)
4. Triceratops: 25.0 km/h (Cretaceous, Herbivore)
5. Brachiosaurus: 20.0 km/h (Jurassic, Herbivore)
6. Stegosaurus: 15.0 km/h (Jurassic, Herbivore)
✨ 面试官反馈
面试官对文件IO处理很满意:"Good implementation! You've handled CSV parsing and sorting well. The code is clean and handles edge cases."
面试技巧分享
在 Meta PE SDE Coding Round 面试中,除了算法实现,面试官还会关注:
1. 代码质量
写出清晰、可读的代码,包含适当的注释和错误处理。
2. 边界条件处理
考虑空字符串、文件不存在、数据格式错误等特殊情况。
3. 算法选择
选择最优的算法,如双指针解决回文问题,排序算法处理数据分析。
4. 文件IO处理
正确处理文件读取、CSV解析、异常处理等实际工程问题。
Oavoservice 实时辅助服务
在这次 Meta PE SDE Coding Round 面试中,我们的实时辅助系统发挥了关键作用:
- 算法指导:帮助候选人快速选择双指针算法解决回文问题
- 代码实现:提供完整的Java代码实现
- 文件IO:协助处理CSV文件读取和解析
- 错误处理:确保代码包含适当的异常处理
结语
Meta PE SDE Coding Round 的两道题目虽然看似简单,但考察了候选人的基础算法能力和实际工程经验。回文判断考察双指针算法,数据分析考察文件IO和数据处理能力。在面试中,能够快速实现并处理边界条件,展现了候选人的编程功底。
如果你正在准备 Meta 或其他公司的技术面试,欢迎联系 Oavoservice。我们拥有丰富的面试经验和专业的辅助团队,能够在你最需要的时候提供及时有效的帮助。
Oavoservice - 让每一次面试都成为成功的机会!
需要辅助的同学随时dd哦,vo开始前支持mock!