前言
最近,字节跳动的青训营再次扬帆起航,作为第二次参与其中的小北,深感荣幸能借此机会为那些尚未了解青训营的友友们带来一些详细介绍。青训营不仅是一个技术学习与成长的摇篮,更是一个连接未来与梦想的桥梁~
1、报名方式
2、考核内容
在指定的题库中自主选择不少于 15 道算法题并完成解题,其中题目难度分配如下:
- 简单题不少于 10 道
- 中等题不少于 4 道
- 困难题不少于 1 道
eg:解答代码(困难2题)
1、二进制之和(困难)
# 问题描述 给定两个二进制字符串,返回他们的和(用十进制字符串表示)。输入为非空字符串且只包含数字 1 和 0 ,请考虑大数问题。时间复杂度不要超过 O(n^2),其中 n 是二进制的最大长度。 ## 输入格式 每个样例只有一行,两个二进制字符串以英文逗号“,”分割 ## 输出格式 输出十进制格式的两个二进制的和 **输入样例**: 101,110 **输出样例**: 11 **数据范围**: 每个二进制不超过 100 个字符,JavaScript 语言下请考虑大数的情况。
问题分析:
- 函数签名:string addBinary(const string &a, const string &b):这个函数接收两个二进制字符串,并返回它们的十进制和作为字符串。
- 变量初始化:string result;:用于存储二进制加法的中间和最终结果(在反转之前)。int carry = 0;:初始化进位为0。int i = a.size() - 1; 和 int j = b.size() - 1;:分别初始化两个字符串的索引,从末尾开始遍历。
- 循环逻辑:while (i >= 0 || j >= 0 || carry):当任一字符串还有未处理的位或存在进位时,继续循环。在循环内部,首先处理进位,然后根据索引 i 和 j 的有效性,将对应位置的字符转换为数字并加到 sum 上。更新进位 carry 和结果字符串 result。
- 结果处理:reverse(result.begin(), result.end());:由于是从字符串末尾开始构建结果,因此最后需要反转字符串。long long decimalSum = stoll(result, 0, 2);:将二进制字符串转换为十进制长整数。这一步实际上是多余的,因为题目要求返回的是十进制字符串,而不是长整数。return to_string(decimalSum);:将十进制长整数转换回字符串并返回。由于前面的 stoll 转换是多余的,这一步也可以优化为直接返回 result 字符串(在反转之后)。
初始代码:
def solution(expression): # Please write your code here return -2 if __name__ == "__main__": # You can add more test cases here print(solution("1+1") == 2) print(solution("3+4*5/(3+2)") == 7) print(solution("4+2*5-2/1") == 12) print(solution("(1+(4+5+2)-3)+(6+8)") == 23)
手搓代码:
import java.util.Stack; public class Main { public static int solution(String expression) { Stack<Integer> numStack = new Stack<>(); Stack<Character> opStack = new Stack<>(); // 遍历表达式 for (int i = 0; i < expression.length(); i++) { char c = expression.charAt(i); // 如果是数字,将其转换为整数并压入数字栈 if (Character.isDigit(c)) { int num = 0; while (i < expression.length() && Character.isDigit(expression.charAt(i))) { num = num * 10 + (expression.charAt(i) - '0'); i++; } i--; numStack.push(num); } // 如果是左括号,直接压入运算符栈 else if (c == '(') { opStack.push(c); } // 如果是右括号,进行计算直到遇到左括号 else if (c == ')') { while (opStack.peek() != '(') { char op = opStack.pop(); int num2 = numStack.pop(); int num1 = numStack.pop(); if (op == '+') { numStack.push(num1 + num2); } else if (op == '-') { numStack.push(num1 - num2); } else if (op == '*') { numStack.push(num1 * num2); } else if (op == '/') { numStack.push(num1 / num2); } } opStack.pop(); } // 如果是运算符,根据优先级进行处理 else if (isOperator(c)) { while (!opStack.isEmpty() && precedence(c) <= precedence(opStack.peek())) { char op = opStack.pop(); int num2 = numStack.pop(); int num1 = numStack.pop(); if (op == '+') { numStack.push(num1 + num2); } else if (op == '-') { numStack.push(num1 - num2); } else if (op == '*') { numStack.push(num1 * num2); } else if (op == '/') { numStack.push(num1 / num2); } } opStack.push(c); } } // 处理剩余的运算符 while (!opStack.isEmpty()) { char op = opStack.pop(); int num2 = numStack.pop(); int num1 = numStack.pop(); if (op == '+') { numStack.push(num1 + num2); } else if (op == '-') { numStack.push(num1 - num2); } else if (op == '*') { numStack.push(num1 * num2); } else if (op == '/') { numStack.push(num1 / num2); } } // 返回数字栈的栈顶元素即为结果 return numStack.pop(); } // 判断是否为运算符 public static boolean isOperator(char c) { return c == '+' || c == '-' || c == '*' || c == '/'; } // 定义运算符的优先级 public static int precedence(char op) { if (op == '+' || op == '-') { return 1; } else if (op == '*' || op == '/') { return 2; } return -1; } public static void main(String[] args) { // You can add more test cases here System.out.println(solution("1+1") == 2); System.out.println(solution("3+4*5/(3+2)") == 7); System.out.println(solution("4+2*5-2/1") == 12); System.out.println(solution("(1+(4+5+2)-3)+(6+8)") == 23); } }
AI调试:
def solution(binary1, binary2): # 使用int函数将二进制字符串转换为整数 num1 = int(binary1, 2) num2 = int(binary2, 2) sum_result = num1 + num2 # 计算和 return str(sum_result) # 将结果转换为字符串并返回 # 测试用例 print(solution("101", "110") == "11") print(solution("111111", "10100") == "83") print(solution("111010101001001011", "100010101001") == "242420") print(solution("111010101001011", "10010101001") == "31220")
运行结果:
2、查找热点数据(困难)
# 问题描述
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按任意顺序返回答案。
- 1 <= nums.length <= 10^5
- k 的取值范围是 [1, 数组中不相同的元素的个数]
- 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
你所设计算法的时间复杂度必须优于 O(n log n) ,其中 n 是数组大小。
**示例 1**
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
**示例 2**
输入: nums = [1], k = 1
输出: [1]
问题分析:
1、参数:
- vector& nums: 输入的整数数组。
- int k: 需要返回的前k个高频元素的数量。
2、局部变量:
- unordered_map<int, int> freqMap: 用于存储每个数字的频率。
- vector<pair<int,int>> result: 存储哈希表中的键值对(数字及其频率)。
- stringstream ss: 用于构建最终返回的字符串。
3、逻辑流程:
- 构建频率映射: 遍历输入数组 nums,使用 unordered_map 记录每个数字的频率。
- 存储映射到结果向量: 将 freqMap 中的每个键值对(数字及其频率)添加到 result 向量中。
- 排序: 使用 sort 函数对 result 向量进行排序,排序依据是元素的频率(降序)。
- 构建返回字符串: 遍历排序后的 result 向量的前 k 个元素,将它们转换为字符串并使用逗号分隔,存储在 stringstream 中。
- 返回结果: 将 stringstream 中的内容转换为字符串并返回。
最终代码:
import java.util.*;
public class Main {
public static String solution(int[] nums, int k) {
// 使用哈希表记录每个元素的频率
Map<Integer, Integer> freqMap = new HashMap<>();
for (int num : nums) {
freqMap.put(num, freqMap.getOrDefault(num, 0) + 1);
}
// 将频率存储到列表中并按频率排序
List<Map.Entry<Integer, Integer>> resultList = new ArrayList<>(freqMap.entrySet());
resultList.sort((a, b) -> b.getValue().compareTo(a.getValue())); // 按频率降序排序
// 创建结果字符串
StringBuilder sb = new StringBuilder();
for (int i = 0; i < k; i++) {
sb.append(resultList.get(i).getKey());
if (i < k - 1) {
sb.append(","); // 添加逗号分隔
}
}
return sb.toString(); // 返回结果字符串
}
public static void main(String[] args) {
// 测试用例
int[] nums1 = {1, 1, 1, 2, 2, 3};
int[] nums2 = {1};
// 输出结果是否与预期相符
System.out.println(solution(nums1, 2).equals("1,2")); // true
System.out.println(solution(nums2, 1).equals("1")); // true
}
}
结语
在这篇技术博客中,小北与友友们分享了字节跳动青训营的精彩内容,从报名方式到考核内容,再到具体的算法题目示例和解答代码,让我们对青训营有了更深入的了解。通过这些实际的算法题目和解决方案,我们不仅能够学习到编程技巧,还能够感受到解决实际问题的乐趣。
希望这篇博客能够激励更多的技术爱好者参与到青训营中,提升自己的技术水平,同时小北也期待在未来能带给友友们更多有价值的技术分享~
最后,祝愿所有参与青训营的朋友们都能学有所成,技术精进,未来在技术的道路上越走越远。同时,也期待字节跳动青训营能够培养出更多的技术人才,为技术社区注入更多的活力和创新!
感谢友友们的阅读,我们下次再见~