虾皮笔试 虾皮笔试题 20260310 春招笔试真题解析
笔试时间:2026年3月10日
往年笔试合集:
第一题:三角形组合数量
难度:中等
题目描述
有 n(3 ≤ n ≤ 10000)条线段,长度为 l₁, l₂...lₙ。(1 ≤ lᵢ ≤ 1000000)从中取出3条线段组成一个三角形,求一共有多少种不同的组合。三角形条件:任意两边长度和大于第三边。
其他要求
- 时间限制: 3000ms
- 内存限制: 256.0MB
输入描述
第一个参数为线段数量 n,第二个参数为长度数组。
输出描述
输出不同组合的数量。
样例输入
4,[1,1,1,1]
样例输出
4
参考题解
解题思路:
涉及算法:排序 + 双指针。
经典"三数之和"题目的变体。构成三角形的充要条件是:任意两边之和大于第三边。由于只要满足"较短的两条边之和大于最长边",这个条件就一定成立,因此我们首先需要对线段数组进行升序排序。
排序后,我们可以固定最长的一条边作为基准(假设其索引为 k),然后在其左侧寻找两条较短的边(设索引分别为 i 和 j,且 i < j < k)。
使用双指针法:将 i 指向最左侧(索引 0),j 指向 k 的前一个位置(索引 k-1)。如果 nums[i] + nums[j] > nums[k],说明在 i 到 j-1 之间的所有线段,与 j 相加都会大于 nums[k]。此时满足条件的组合数有 j - i 种,记录数量后,将 j 向左移动一位继续判断。如果 nums[i] + nums[j] <= nums[k],说明此时的 i 太小了,需要将 i 向右移动一位以增大两边之和。
Java:
import java.util.Arrays;
public class TriangleCount {
public static int triangleNumber(int[] nums) {
// 1. 对数组进行升序排序
Arrays.sort(nums);
int count = 0;
// 2. 从后往前遍历,固定最长边 k
for (int k = nums.length - 1; k >= 2; k--) {
int i = 0;
int j = k - 1;
// 3. 在 0 到 k-1 之间使用双指针寻找较短的两条边
while (i < j) {
if (nums[i] + nums[j] > nums[k]) {
// 如果满足条件,说明从 i 到 j-1 的元素作为最短边都能和 j、k 构成三角形
count += j - i;
j--; // 移动右指针寻找其他可能性
} else {
i++; // 不满足条件,说明需要更大的偏短边,移动左指针
}
}
}
return count;
}
}
C++:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int triangleNumber(vector<int>& nums) {
// 1. 对数组进行升序排序
sort(nums.begin(), nums.end());
int count = 0;
// 2. 从后往前遍历,固定最长边 k
for (int k = nums.size() - 1; k >= 2; k--) {
int i = 0;
int j = k - 1;
// 3. 在 0 到 k-1 之间使用双指针寻找较短的两条边
while (i < j) {
if (nums[i] + nums[j] > nums[k]) {
// 如果满足条件,说明从 i 到 j-1 的元素作为最短边都能和 j、k 构成三角形
count += j - i;
j--; // 移动右指针寻找其他可能性
} else {
i++; // 不满足条件,说明需要更大的偏短边,移动左指针
}
}
}
return count;
}
Python:
def triangle_number(nums):
# 1. 对数组进行升序排序
nums.sort()
count = 0
# 2. 从后往前遍历,固定最长边 k
for k in range(len(nums) - 1, 1, -1):
i = 0
j = k - 1
# 3. 在 0 到 k-1 之间使用双指针寻找较短的两条边
while i < j:
if nums[i] + nums[j] > nums[k]:
# 如果满足条件,说明从 i 到 j-1 的元素作为最短边都能和 j、k 构成三角形
count += j - i
j -= 1 # 移动右指针寻找其他可能性
else:
i += 1 # 不满足条件,说明需要更大的偏短边,移动左指针
return count
第二题:找出最长回文子串
难度:偏易
题目描述
给你一个字符串 s,找到 s 中最长的回文子串。回文串:字符串向前和向后读都相同。
要求:
- 回文子串的长度是奇数
- 如果存在多个,返回第一个
其他要求
- 时间限制: 3000ms
- 内存限制: 256.0MB
输入描述
一个字符串 s。
输出描述
最长的奇数长度回文子串。如果存在多个,返回第一个。
样例输入
"babad"
样例输出
"bab"
参考题解
解题思路:
涉及算法:中心扩散法。
题目明确要求只寻找长度为奇数的回文子串。奇数长度的回文串有一个特点:它的"中心"必然是一个明确的字符,而不是两个字符之间的间隙。
因此,我们可以遍历字符串中的每一个字符,将其作为回文的中心点,向左和向右同时扩散。在扩散过程中,如果左右字符相同,就继续扩散;如果不相同或者越界,就停止扩散。
记录下扩散过程中得到的最长回文长度。题目要求"如果存在多个,返回第一个",所以只有当新找到的回文串长度严格大于当前记录的最大长度时,才更新结果的起始位置和最大长度。
Java:
public class LongestOddPalindrome {
public static String longestPalindrome(String s) {
if (s == null || s.length() == 0) return "";
int start = 0;
int maxLength = 0;
// 遍历每个字符作为奇数回文串的中心
for (int i = 0; i < s.length(); i++) {
int left = i;
int right = i;
// 向两边扩散,直到越界或左右字符不匹配
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--;
right++;
}
// 退出循环时,左右指针分别多走了一步,实际回文长度为 right - left - 1
int currentLen = right - left - 1;
// 使用严格大于 (>),确保如果有多个长度相同的回文串,只保留最先找到的那个
if (currentLen > maxLength) {
maxLength = currentLen;
start = left + 1; // 记录最长回文串的实际起始索引
}
}
return s.substring(start, start + maxLength);
}
}
C++:
#include <iostream>
#include <string>
using namespace std;
string longestPalindrome(string s) {
if (s.empty()) return "";
int start = 0;
int maxLength = 0;
// 遍历每个字符作为奇数回文串的中心
for (int i = 0; i < (int)s.length(); i++) {
int left = i;
int right = i;
// 向两边扩散,直到越界或左右字符不匹配
while (left >= 0 && right < (int)s.length() && s[left] == s[right]) {
left--;
right++;
}
// 退出循环时,左右指针分别多走了一步,实际回文长度为 right - left - 1
int currentLen = right - left - 1;
// 使用严格大于 (>),确保如果有多个长度相同的回文串,只保留最先找到的那个
if (currentLen > maxLength) {
maxLength = currentLen;
start
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南
查看14道真题和解析