当算法与SQL遇见测试:滑动窗口与排名函数的实战应用
引言
在测试工程师的日常工作中,算法和SQL不仅是面试的敲门砖,更是解决实际问题的利器。今天,我们通过两道经典题目 —— 3. 无重复字符的最长子串 和 178. 分数排名,探讨如何将算法与SQL应用于日志分析、性能监控等测试场景。
算法篇:3. 无重复字符的最长子串
题目描述
给定一个字符串 s,找出其中不含有重复字符的 最长子串 的长度。
测试场景映射
- 日志分析:检测日志中连续无重复错误码的最大序列(如错误码连续不重复的时段分析)。
- 接口测试:验证请求参数的唯一性(如Session ID或Token的连续性检查)。
解题思路
- 滑动窗口:用哈希集合记录窗口内字符,动态调整窗口边界。
- 时间复杂度:O(n),适合处理长文本或日志流。
代码实现
python
复制
def length_of_longest_substring(s: str) -> int:
char_set = set() # 记录窗口内字符
left = 0
max_len = 0
for right in range(len(s)):
# 如果当前字符在集合中,移动左指针直到去重
while s[right] in char_set:
char_set.remove(s[left])
left += 1
# 添加当前字符并更新最大长度
char_set.add(s[right])
max_len = max(max_len, right - left + 1)
return max_len
测试用例设计
python
复制
def test_length_of_longest_substring():
# 场景1:常规测试
assert length_of_longest_substring("abcabcbb") == 3 # "abc"
# 场景2:全重复字符
assert length_of_longest_substring("bbbbb") == 1 # "b"
# 场景3:空字符串
assert length_of_longest_substring("") == 0
# 场景4:中间有重复
assert length_of_longest_substring("abba") == 2 # "ab" 或 "ba"
SQL篇:178. 分数排名
题目描述
为 Scores 表中的分数生成排名。若两个分数相同,则排名相同,且下一个排名不跳过(即“密集排名”)。
测试场景映射
- 性能测试:统计接口响应时间的TOP 10排名。
- 测试报告:分析测试用例执行失败率的排名。
解题思路
- 窗口函数:使用
DENSE_RANK()实现密集排名。 - 排序规则:按分数降序排列,相同分数共享排名。
SQL实现
sql
复制
SELECT
Score,
DENSE_RANK() OVER (ORDER BY Score DESC) AS 'Rank'
FROM Scores;
测试用例设计
sql
复制
-- 测试数据
CREATE TABLE Scores (
Id INT PRIMARY KEY,
Score DECIMAL(3,2)
);
INSERT INTO Scores (Id, Score) VALUES
(1, 3.50),
(2, 3.65),
(3, 4.00),
(4, 3.85),
(5, 4.00),
(6, 3.65);
-- 执行查询并验证结果
SELECT * FROM Scores ORDER BY Score DESC;
实战应用
场景1:日志分析
-
问题:如何检测日志中连续无重复错误码的最大序列?
-
解决方案:
- 将日志按时间排序,提取错误码序列。
- 使用滑动窗口算法计算最长无重复子串长度。
- 输出结果并生成告警(如连续无重复错误码超过阈值)。
场景2:性能测试排名
-
问题:如何统计接口响应时间的TOP 10排名?
-
解决方案:
- 从性能测试结果表中提取响应时间数据。
- 使用
DENSE_RANK()函数生成排名。 - 输出TOP 10结果并生成可视化报告。
总结
通过这两道题目,我们不仅掌握了 滑动窗口 和 窗口函数 的核心思想,还将其应用于测试工程师的实际工作场景。这种 算法 + SQL + 测试场景 的结合,能极大提升我们的技术能力和面试竞争力。
延伸思考
- 算法题:如何优化滑动窗口的空间复杂度(如用字典代替集合)?
- SQL题:如果要求相同分数排名相同但下一个排名跳过(如1,1,3),如何修改SQL?
答案参考:
-
用字典存储字符最后一次出现的位置:
python
复制
def length_of_longest_substring(s: str) -> int: char_map = {} # 记录字符最后出现的位置 left = 0 max_len = 0 for right in range(len(s)): if s[right] in char_map: left = max(left, char_map[s[right]] + 1) char_map[s[right]] = right max_len = max(max_len, right - left + 1) return max_len -
改用
RANK()函数:sql
复制
SELECT Score, RANK() OVER (ORDER BY Score DESC) AS 'Rank' FROM Scores;