1. 大一算法练习记录(Day2)--两道算法题总结
刚接触算法的新手往往会被各种概念和题目绕晕,我大一那年也经历过这个阶段。今天翻到当时的练习笔记,决定把第二天的两道典型题目整理出来,用现在更成熟的理解重新解析解题思路,希望能给同样在刷题路上的同学一些参考。
这两道题都来自洛谷平台,分别是三连击问题和另一个基础排序题。选择它们是因为涵盖了暴力枚举和基础算法思想,非常适合算法入门者建立解题思维框架。下面我会逐题分析题目要求、解题思路、代码实现和优化方向,过程中会穿插当时踩过的坑和现在回头看可以改进的地方。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三连击问题详解
2.1 题目重述与需求分析
题目要求找出所有满足以下条件的三位数ABC、DEF和GHI:
- 每个三位数都没有重复数字
- ABC:DEF:GHI = 1:2:3
- 三个数合起来使用了1-9的所有数字且不重复
第一次看到这个题目时,我花了20分钟才真正理解题意。关键点在于:
- 比例关系意味着DEF=2×ABC,GHI=3×ABC
- 数字1-9必须恰好各出现一次,不能有0
- 每个三位数自身也不能有重复数字
2.2 暴力解法实现
最直接的思路就是遍历所有可能的三位数ABC,然后计算DEF和GHI,最后检查数字使用情况。这是我当时写的第一个版本:
c复制#include <stdio.h>
int check(int a, int b, int c) {
int digits[10] = {0};
// 检查a
while(a > 0) {
int d = a % 10;
if(d == 0 || digits[d]) return 0;
digits[d] = 1;
a /= 10;
}
// 同样方式检查b和c
// ...
return 1;
}
int main() {
for(int abc = 123; abc <= 329; abc++) {
int def = abc * 2;
int ghi = abc * 3;
if(check(abc, def, ghi)) {
printf("%d %d %d\n", abc, def, ghi);
}
}
return 0;
}
优化点:
- 循环范围从123开始,因为最小的ABC是123(987/3=329)
- 提前终止条件:当GHI超过三位数时停止
2.3 算法优化思路
后来我发现这个解法还有优化空间:
- 可以在计算def和ghi前先检查abc是否有重复数字
- 使用位运算代替数组可以稍微提升速度
- 并行检查三个数的数字使用情况
优化后的check函数:
c复制int check_optimized(int a, int b, int c) {
int mask = 0;
while(a > 0) {
int d = a % 10;
if(d == 0 || (mask & (1 << d))) return 0;
mask |= (1 << d);
a /= 10;
}
// 同样处理b和c
// ...
return mask == 0x1FF; // 检查1-9是否全部使用
}
3. 基础排序问题解析
3.1 题目场景还原
第二题是经典的排序问题:给定n个整数,请将它们从小到大排序后输出。虽然看起来简单,但作为新手,我在这道题上犯了不少错误。
3.2 多种排序算法实现
3.2.1 冒泡排序实现
我第一个尝试的是冒泡排序,因为它的逻辑最直观:
c复制void bubble_sort(int arr[], int n) {
for(int i = 0; i < n-1; i++) {
for(int j = 0; j < n-i-1; j++) {
if(arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
易错点:
- 内循环的边界条件容易写错成j<n-1
- 忘记外层循环的优化(n-i-1)
3.2.2 快速排序进阶
后来学习了快速排序,虽然代码复杂些但效率更高:
c复制int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = low - 1;
for(int j = low; j < high; j++) {
if(arr[j] < pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i+1], &arr[high]);
return i+1;
}
void quick_sort(int arr[], int low, int high) {
if(low < high) {
int pi = partition(arr, low, high);
quick_sort(arr, low, pi-1);
quick_sort(arr, pi+1, high);
}
}
调试经验:
- 基准值(pivot)选择很重要,最初我选第一个元素遇到有序数组时退化到O(n^2)
- 递归终止条件容易漏掉low<high的判断
4. 算法练习方法论
4.1 刷题的有效方法
经过这些练习,我总结出几个有效的学习方法:
- 先理解题目再动手,画图辅助理解
- 从最直观的解法开始,不要一开始就追求最优解
- 写完后主动思考优化空间
- 记录每种解法的时间/空间复杂度
4.2 常见问题排查
新手常遇到的问题和解决方法:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 输出结果不对 | 边界条件处理不当 | 测试最小/最大输入情况 |
| 程序运行超时 | 算法复杂度太高 | 分析时间复杂度,选择更优算法 |
| 内存超出限制 | 不必要的空间消耗 | 检查是否有冗余数据结构 |
5. 练习资源推荐
对于刚入门算法的同学,我推荐以下练习路径:
- 洛谷新手村题目
- LeetCode探索初级算法
- 《算法导论》配套练习
重点掌握:
- 基础排序算法
- 简单查找算法
- 基本数据结构应用
每天保持2-3题的练习量,坚持一个月就能看到明显进步。我当时坚持了100天每日练习,编程能力有了质的飞跃。记住,算法学习是个渐进过程,不要因为初期困难而放弃。
