
程序设计实践 Week1 解题记录

前言
Week 1 的题目太菜了, 一天就 AK
了.
尽量选了一些相对难的题目来讲.
1. 两数之和
题意简述
给定一个不含重复元素的升序数组 a
, 求出所有
题目保证组合唯一.
Solution
不需要双指针, 直接用 unordered_map
记录出现过的数即可.
在a[i]
, 查找 target - a[i]
在 map
中是否出现过.
时间复杂度a
不是有序的, 那么这种做法比双指针优, 因为不需要排序.
AC Code:
|
2. 三数之和
题意简述
找出所有数对, 满足:
不允许有重复数字.
Solution
固定
为了在线性复杂度内求出
令
- 若
, 说明 太小, 令 . - 若
, 说明 太大, 令 . - 若
, 输出 即可, 去重后令 和 .
持续以上过程直至
总的时间复杂度为
AC Code:
|
3. 四数之和
题意简述
找出所有数对, 满足:
不允许有重复数值.
Solution
固定
时间复杂度
AC Code:
|
4. 汉诺塔I
题意简述
经典问题.
有三根柱子和不同大小的圆盘, 起始时所有圆盘都堆叠在第一根柱子上, 大的在下, 小的在上. 求将所有圆盘移动到第三根柱子上的最少移动步骤.
移动遵循以下规则:
- 一次只能移动一个圆盘.
- 大盘不能在小盘上面. (目标柱上)
- 可以借助中间柱子.
Solution
现对题目进行形式化描述与推导.
令
- 若
, 则直接移动 上的圆盘到 上, 也就是打印 A->C
. - 若
: - 先把
个盘子从 移动到 上, 这个时候需要 来当辅助柱子, 也就是执行 . - 然后,
上就剩最大的盘子了, 把它移动到 上, 打印 A->C
. - 最后, 把
个盘子从 移动到 上, 这个时候需要 来当辅助柱子, 也就是执行 .
- 先把
递归这个 Hanoi
函数, 即可求出最少移动步数.
时间复杂度
AC Code:
|
5. 放苹果
题意简述
求把
Solution
设
- 若
, 则 (空盘子的方案数为 ). - 若
, 则 (没有苹果的方案数为 ). - 特别地, 有
(空盘子和空苹果的方案数为 ).
以上为边界情况, 接下来考虑递推求解
首先, 如果
, 最多只能用到 个盘子(各放 1 个苹果), 也就是说 “ 个苹果放到 个盘子” 这个问题等价于 “ 个苹果放到 个盘子”, 所以 . 否则, 我们作如下讨论:
- 这
个盘子都不能放空. 也就是说, 每个盘子至少要放一个苹果.
为了保证这一点, 我们可以先在各个盘子上放个苹果, 然后再把剩下的 个苹果放到 个盘子上.
方案数为. - 这
个盘子至少有一个为空. 那只要把 个苹果放到 个盘子上即可.
方案数为.
于是, 我们可以得到:.
- 这
递推求解即可, 答案为
时间复杂度
AC Code:
|
6. 递归求波兰表达式
题意简述
给定一行前缀表达式, 请你计算算式结果.
Solution
虽然题目叫 “递归求“, 但我用了更好看的写法(maybe): 栈.
观察即可得到这样的做法:
从右往左扫描表达式, 遇到数字就压栈, 遇到符号就取出栈顶的两个数字进行运算, 并将运算结果压栈.
最后栈顶元素即为结果.
需要注意, 取出栈顶数字的时候, 先取出来的是左操作数, 后取出来的是右操作数.
可以使用 stod()
函数方便地把字符串转为 double
类型.
AC Code:
|
7. 算式表达式
题意简述
给定一行算式, 运算数在+
和 *
, 求算式对
算式一共有
Solution
一开始没看数据范围, 想用 Python
的 eval()
函数, 结果吃了一发 RE
.
其实这题很简单, 只要想到处理 +
和 *
运算优先级的方法就行. 令 ans
表示当前计算的答案, cur
表示当前累计的乘法运算的结果, 从左到右扫描运算符:
- 对于
*
: 将cur
乘以当前数字. - 对于
+
: 将ans
加上cur
, 然后将cur
置为.
最后输出 (ans + cur) % MOD
即可.
AC Code:
|
8. 二进制密码锁
题意简述
给定两个 01 字符串
Solution
将
我们从左到右扫描
在这个策略下, 对于
怎么办呢? 那就对
AC Code:
|
9. 熄灯问题
题意简述
给定一个
输出字典序最小的对
其实也就是二维的 “二进制密码锁”.
Solution
显然,
显然, 若
因此, 只需要枚举
最后判断
时间复杂度 O(
AC Code:
// 太好了只有 6 * 6, 不需要考虑状压 |
10. 拨钟问题
题意简述
有
Solution
for
循环枚举所有状态还是有点非人类了, 我选择 BFS
.
思路很简单, 开一个结构体 Status
表示状态, 其中 c
存当前的钟的状态, step
存初态到这个状态的操作方案, correct
函数用于判断是否所有钟都到 12
点了.
另外, 为了防止重复搜索, 需要一个 vis
数组记录状态是否被搜索过.
再写一个简单的 to_int
函数用于把钟的状态映射为唯一的 int
数即可. 最简单的方式就是把 c
看成一个四进制数.
然后就没啥好说的了.
时间复杂度
AC Code:
|
11. 求排列的逆序数
题意简述
给定一个长为
逆序对
Solution
众所周知求逆序对可以用归并排序或者树状数组.
但我已经忘记树状数组怎么写了, 所以用的归并排序.
归并排序时, 我们能直接根据要插入的元素的位置计算出它的逆序对数, 累加这个答案进计数器即可.
归并排序没啥好说的, 计算方式见代码注释.
AC Code:
|
12. 最小预算值
题意简述
给定长为
Solution
“最小化最大值”, 经典的二分答案转判定.
有两个点需要注意:
- 二分时, 初始边界
不应设为 , 而应是 . - 二分有多种写法, 要注意边界的判定和答案的选择, 这里推荐用另一个计数器
来记录可行的答案, 收缩区间时把端点 或 都排除, 这样就不用纠结答案是落在 还是 了.
AC Code:
|
13. 林克的蛋糕
题意简述
给定
与上一题的不同之处在于,
Solution
浮点数二分, 和整数二分的思路一样, 只需要改一下二分条件即可.
整数二分条件一般是 l < r
或 l <= r
, 浮点数二分改成 r - l > eps
, 其中 eps
是自定义的精度.
AC Code:
|
- 标题: 程序设计实践 Week1 解题记录
- 作者: Coast23
- 创建于 : 2025-06-30 09:19:13
- 更新于 : 2025-07-03 14:16:46
- 链接: https://coast23.github.io/2025/06/30/程序设计实践-Week1-解题记录/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。