1. 大一算法练习记录(Day2)--两道算法题总结
刚接触算法的新手往往会被各种复杂概念吓退,但真正的成长恰恰来自于每天坚持解决具体问题。作为计算机专业大一学生,我选择用最笨也最有效的方法——每天记录两道典型算法题的解题过程。今天分享的这两道来自洛谷平台的题目,看似简单却暗藏玄机,完美展现了算法思维从雏形到成熟的演变轨迹。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三连击问题深度解析
2.1 问题重述与数学建模
洛谷P1008题目要求找出所有满足以下条件的9位数组合:由三个三位数A、B、C构成,且满足B=2A、C=3A,同时这三个数拼接后恰好使用1-9各一次。这本质上是个排列组合问题,但直接暴力枚举9!种排列显然不现实。
通过数学分析可以大幅缩小搜索空间:
- A的范围锁定在123-329之间(因为C=3A≤987)
- 三个数的数字并集必须正好是1-9的无重复全集
c复制for(int a=123; a<=329; a++){
int b = 2*a, c = 3*a;
// 数字校验逻辑
}
2.2 高效数字校验算法
校验数字是否满足1-9不重复的标准有多种实现方式:
位图法(最优解)
c复制int check(int a, int b, int c){
int mask = 0;
while(a) { mask |= 1<<(a%10); a/=10; }
while(b) { mask |= 1<<(b%10); b/=10; }
while(c) { mask |= 1<<(c%10); c/=10; }
return mask == 0b1111111110; // 二进制位1-9全为1
}
对比其他方法:
- 字符串拼接+排序法:需要额外内存和排序时间
- 数组计数法:需要遍历计数数组检查
实测位图法比排序法快3倍,内存节省50%
2.3 边界条件与优化技巧
- 数字0的排除:通过初始范围限制自然规避
- 提前终止条件:当检测到重复数字时可立即跳出当前循环
- 循环步长优化:A的增量可以设为3的倍数(因为C=3A需保持整数)
3. 数字统计问题实战
3.1 问题变形分析
洛谷P1179要求统计区间[L,R]内所有整数中数字2出现的次数。看似简单,但直接遍历每个数字逐位检查的方法(O(nlogn)复杂度)在大数据量时会超时。
数学归纳法发现规律:
- 个位出现频率:每10个数出现1次
- 十位出现频率:每100个数出现10次
- 百位出现频率:每1000个数出现100次
3.2 分位数统计算法
c复制int countDigit(int n, int d){
int cnt = 0;
for(long long i=1; i<=n; i*=10){
int higher = n/(i*10);
int lower = n%i;
int curr = (n/i)%10;
cnt += higher*i;
if(curr > d) cnt += i;
else if(curr == d) cnt += lower + 1;
}
return cnt;
}
复杂度分析:
- 时间复杂度:O(logn) 仅与数字位数相关
- 空间复杂度:O(1) 常数级额外空间
3.3 特殊案例处理
- 数字0的统计需要额外处理最高位情况
- 大数运算时注意整数溢出(使用long long)
- 左闭右闭区间转换为countDigit(R)-countDigit(L-1)
4. 算法思维进阶训练
4.1 从具体问题到抽象模式
通过这两道题可以提炼出通用解题框架:
- 问题重述:用自己的语言明确输入输出
- 暴力解法:先给出最直观的解决方案
- 寻找规律:通过小规模案例发现数学模式
- 优化实现:选择合适的数据结构和算法
- 边界测试:考虑极值、特殊值情况
4.2 调试技巧实录
- 打印中间变量:在复杂循环中输出关键变量值
- 单元测试:对每个函数编写测试用例
- 对拍验证:用暴力算法与优化算法交叉验证
c复制// 单元测试示例
void test_countDigit(){
assert(countDigit(20,2) == 3);
assert(countDigit(99,9) == 20);
assert(countDigit(100,0) == 11);
}
5. 洛谷刷题经验分享
5.1 题目选择策略
- 按标签筛选:如"模拟"、"数学"、"枚举"
- 难度递进:从普及-开始逐步提高
- 同类题组:一次性解决相似题型
5.2 提交注意事项
- 多次WA时:先检查样例输入输出格式
- TLE时:考虑算法复杂度是否达标
- RE时:检查数组越界或递归爆栈
5.3 效率提升工具
- 代码模板:准备常用IO优化代码段
c复制#define fastio ios::sync_with_stdio(false);cin.tie(0)
int main(){
fastio;
// 解决cin/cout速度问题
}
- 本地测试脚本:自动生成边界测试数据
- 性能分析器:gprof定位热点函数
6. 算法学习路线建议
从这两道题延伸出的学习路径:
- 基础语法:熟练掌握C++ STL容器
- 数学基础:数论、组合数学入门
- 经典算法:排序、查找、位运算
- 竞赛技巧:复杂度分析、优化方法
推荐配合《算法竞赛入门经典》进行系统学习,每个知识点配套3-5道洛谷练习题。记录错题本时不仅要记正确解法,更要记录自己的原始思路偏差。
