《剑指 offer》刷题记录之二:字符串 & 链表
本篇博客为《剑指 offer》一书的刷题笔记(第二部分)。
面试题 5:替换空格
题目:请实现一个函数,把字符串
s
中的每个空格替换成 "%20"。
示例
输入:s = "We are happy." |
限制:\(0 \le s \le 100000\)
思路及代码
这道题的关键在于如何执行替换操作,如果我们使用常规的从前往后遍历字符串替换空格,由于需要将 1 个字符替换为 3 个字符,因此替换时需要将当前字符后面的所有字符整体后移,这会导致总的时间复杂度达到 \(O(n^2)\),显然并不是我们想要的结果(上述思考是原书中针对 C++ 提出的,实际上 java 和 python 中字符串不可更改,会自然而然地想到创建新的字符串)。
为了减小时间复杂度,我们可以创建一个辅助数组,提前预留出位置用于替换。数组的长度设为原字符串长度的 3 倍。遍历字符串,将其依次填入数组中,发现空格就替换,记录当前替换后字符串的总长度,最后将数组转化为新的字符串。
上述解法的 java 实现如下:
class Solution { |
上述方法用 StringBuilder
也可以实现。而对于 python,可以通过 list
实现,如下所示:
class Solution: |
本方法的时间复杂度为 \(O(n)\),空间复杂度也为 \(O(n)\)。实际上,原书中针对 C++ 给出的解法为先按照空格数扩展原字符串,再从后往前遍历,这样可以避免多次移动。
PS:%20
是 URL 的空格编码,表示一个普通空格(本质是 ASCII 码),而
则是一种 HTML 的字符实体编码,表示 Non-breaking space,即不被折断的空格,一般用来占位,其 Unicode 码对应为 U+00A0
(无 ASCII 码,UTF-8 码为 C2A0
),更详细的说明请查看维基百科。
面试题 6:从尾到头打印链表
题目:输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例
输入:head = [1,3,2] |
限制:\(0 \le 链表长度 \le 100000\)
思路及代码
在不改变链表结构的前提下,如果我们遍历链表,遍历的顺序是从头到尾,而要求的输出顺序是从尾到头。即第一个遍历到的节点在最后一个输出,最后一个遍历到的节点在第一个输出,这是典型的“后进先出”,我们可以使用栈来实现这种顺序。
上述方法的 java 实现如下:
/** |
上述方法的时间复杂度为 \(O(n)\),因为正向遍历一遍链表,栈弹出相当于反向遍历一遍链表,空间复杂度为 \(O(n)\),因为额外使用了一个栈来存储链表中的每个节点。python 可以使用 list
和其切片特性实现栈的操作。
除了栈,我们还可以使用递归来解决上述问题,因为递归本质上就是一个栈结构。每访问到一个节点的时候,先递归输出它后面的节点,再输出该节点自身,这样链表的输出结果就反过来了。
上述解法的 python 实现如下:
# Definition for singly-linked list. |
该方法的时间复杂度和空间复杂度同样为 \(O(n)\)。需要注意,由于该递归并非尾递归,所以当链表非常长的时候,会导致函数调用的层级很深,可能导致函数调用栈溢出。相比较而言基于栈实现的代码的鲁棒性要更好一些。