题目重点:给文本和最大宽度,先明确排版是否保留空格及是否按词换行。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版等宽、每字符一列,保留全部空格, 显式换行;超过width硬折行,不采用单词重排。
- 空字符串一行,末尾 产生最后空行。Unicode宽字、tab、CRLF与真实字体未纳入,不能称真实Doc排版。
解题路线
- split按 保留尾部空段,每段len为L,需要max(1,ceil(L/width))行;空段也代表显式空行。
- 逐字符状态机可独立核验:列满后仅在下一个普通字符到来时新增折行,遇 直接新增行并重置列。因此恰好width后跟 不应额外生成折行。
- 按词换行则要维护词长度和行剩余宽度,定义多空格折叠、长词拆分、连字符。比例字体需要测量glyph advance/换行机会,简单字符数无法替代。
手动走一遍
width3,abc def为2行,不是3行;abc 末尾空行使2行。四个空格width3需2行,不能strip后认为只1行。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def line_count(text,width):
# Each char occupies one column; spaces retained; newline starts a new line.
# Long runs hard-wrap. A trailing newline creates an empty final line.
if width<=0:raise ValueError("positive width required")
return sum(max(1,(len(line)+width-1)//width) for line in text.split("\n"))
复杂度
O(L)时间/O(L)split辅助空间;逐字符实现可O(1)辅助,L文本字符数。
易错点与追问
容易失分的边界
- split()无参数会丢空格和显式空行。
- 把ceil(0/width)=0直接相加会漏空段。
继续深挖
- 按词换行时输入a空格空格b应保留还是折叠?
- tab按当前列跳tab stop,为何不能固定算一个字符宽?
