PAT 1001-1010 题解

早期部分代码用Java实现。由于PAT虽然支持各种语言,但只有C/C++标程来限定时间,许多题目用Java读入数据就已经超时,后来转投C/C++。浏览全部代码:请戳

本文谨代表个人思路,欢迎讨论;)

1001. A+B Format (20)

题意

格式化输出两数之和。

分析

理清输出逻辑即可。

1002. A+B for Polynomials (25)

题意

给定两多项式,相加并格式化输出结果。

分析

两种思路

  • 1.采用链表的处理方式;
  • 2.预设好int[1005]的数组,用下标表示次方,数组中元素值表示对应系数。

第一种方法某种程度上看能节省空间,实现上需要注意操作链表时,循环时的越界问题; 方法二用空间换取时间,且实现上更不容易出错。同时,由于浮点数本身精确位数不够,在判定两浮点数相加是否为0时, 需要对结果值取绝对值后,与1e-6做对比。

1003. Emergency (25)

题意

求两个城市之间的加权最短路径。在有多个最短路径记录的情况下,选择路径中所有节点的权重值之和最小的。

分析

Dijkstra算法的变型实现。两种思路:

  • 1.计算最短路时,在每个节点上用链表preList记下所有最短路径的前节点。 完成计算后,对preList做dfs获得每条最短路径的权重值之和,比较后得到结果;
  • 2.计算最短路径时,在节点上,除了记录最短路径中前一个节点preNode之外,还对应的记录当前的最短路径上所有节点的权重值之和, 这就不用在Dij完成之后再做dfs了,过程中已经找到了最优解。

相比之下,方法2明显更简洁。当然,虽然方法2的思路很通用,还需要确定,这一加权的判定条件是能够迭代处理的。

1004. Counting Leaves (30)

题意

计算给定的树各个层级叶子节点的个数

分析

先构建树,鉴于题目的空间限制不严格,可以使用邻接矩阵的方式定义树结构。然后使用dfs遍历树的节点,并记录每层的叶子节点数量。 可以看到,时间空间的trade-off不仅仅是性能上的提升,也会影响带代码实现的复杂程度。

1005. Spell It Right (20)

题意

计算一个数(<=10^100)的各个位数之和,并用英语按位输出。比如15输出为one five.

分析

简单题,输出的实现上实际上就用到了Hash思想。

1006. Sign In and Sign Out (25)

题意

每个人来到实验室和离开实验室的时间都有记录。找到其中最早来实验室和最晚离开实验室的时间。

分析

逻辑上很简单的一个题,遍历所有数据,找到其中最大和最小的值即可。稍微要处理的就是时间。 由于input中给出的是HH:MM:SS的格式,在比较时需要将其换算为int值。实际上,使用C语言读入更方便,scanf("%d:%d:%d", &h, &m, &s); 然后计算出time = 3600*h + 60*m + s,时间比较就没有问题了。在最终的输出时再做对应的转换即可。 而在Java语言中,使用到了String的split方法划分子串和Integer.parseInt()转String为int。

1007. Maximum Subsequence Sum (25)

题意

给出一组由正负整数组成的序列,求出拥有最大和的连续子序列。

分析

最暴力的算法是两个循环的O(n^2);进一步要使用分治的思想,可以得到O(n*logn);更好的方法可以达到O(n),也可以将它看做分治思想。关键在于数学归纳的证明,编程实现非常简单:假定[0, n-1]的最大连续子串已经求出了,要求[0,n]的最大连续子串。

  • 1.如果[0, n-1]中最大子串不包含最右的数字,则判定原最大子串的和包含最右点的最大子串 + a[n]的和的大小。取大的那个作为[0, n]的最大子串,并保持一个包含最右点的最大子串
  • 2.如果[0, n-1]中最大子串包含最右的数字,则[0, n]的最大子串为原最大子串+a[n]。

实际上,算法的核心是维持了两个量的记录,即当前的最大子串,以及当前包含最右点的最大子串

更多讨论参见博文《分治、时间空间的权衡:最大合的连续字串问题 (PAT 1007) 》

1008. Elevator (20)

题意

给出电梯的行进路径,上下的速度和每层停留时间,计算总时间。

分析

简单的模拟题。

1009. Product of Polynomials (25)

题意

求两个多项式的乘积。

分析

参见PAT1002,使用数组存储虽然空间占用稍大,但比链表实现要便捷很多。

1010. Radix (25)

题意

给定两个数,其中单个位置上的数值范围可以为[0-z]。指定其中一个数的进制,试确定是否存在可能的进制让两数的实际值相等。

分析

此题没有交代清楚input中radix的取值范围以及对一位数有多重可能radix的情况如何输出,坑比较大。下面是需要注意的点。

  • 1.input中两个数字可以是10位数,虽然没有告诉radix的范围,但在9*10^10 10 1 200这个示例中,可以看到结果的radix也可以是很大的。从这个角度看,代码中将radix和两个数值都设定为longlong是合适的选择。
  • 2.在计算另一个数的radix时,简单的遍历[2, 10^18]会超时。单调的区间很自然想到使用二分查找。
  • 3.二分查找的上下界确定能减少耗时:下界选数字的所有位上的最大值+1;上界容易想当然的认为就是题中给定了radix的数的值。实际上,示例11 b 1 10就是一个反例,原因在于这个假设忽略了一位数的可能性,解决方案是在取给定radix的数值和下界中较大的那个数。
  • 4.在二分查找时,不可直接计算出某个radix下数的值,因为可能会longlong溢出。于是需要用特定的compare函数,在累加的过程中判定是否大于另一个数。算是一种剪枝。
  • 5.还有一个条件:当两个数都是1时,输出2.当两个数相等且不为1时,输出题中给出的radix。(这是从其他人的结题报告中看到的,完全不理解=。=)

注意好这些方面,应该能ac了。保重。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值