单链表面试题
假设我们有一个字符串:MALAYALAM,每个字符都是每个节点的数据部分,所以我们将有一个大小为 9 的列表。我们如何知道该列表是否是回文。
约束:
- 我们不知道列表长度。
- 不要对整个列表或一半列表使用临时内存(数组或堆栈或其他列表)。使用少量临时字符是可以接受的。
- 列表修改是可以的,只要我们在操作结束时有原始列表即可。
想到的解决办法不多,想和大家讨论一下。并且它是单链表。
谢谢&平均值, 〜卡尔文
say we have a string: MALAYALAM, and each char is data part of each node, so we will have a list of size 9. How do we know whether the list is palindrome or not.
constraints:
- we donot know list length.
- donot use temporary memory(array or stack or another list) for whole list or half of list. usage of few temp chars is acceptable.
- list modification is okay, as long as we have original list by end of operation.
I've few solutions in mind, thought of discussing with everyone. And it is single linked list.
Thanks & Rgds,
~calvin
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我的解决方案:采用快速和慢速指针,反转列表的一半并与另一半进行比较。并将反转的一半反转,以便列表看起来像原始列表。我正在寻找更好的解决方案。
编辑:因为我找不到更好的溶胶。
my solution: take fast and slow ptrs, reverse half of the list and compare with another half. And reverse the reversed half so that list will look like original. I'm looking for better solution.
edit: since i couldn't find any better sol.
下面应该在 O(n) 内完成
您可以通过记录列表的长度并在达到列表的一半后停止比较来改进此解决方案。
如果字符串中的字符数大于允许的最大堆栈深度,则此操作将不起作用。在这种情况下,更改列表将按如下方式进行...
找出列表的长度。
一旦你到达中间,
The following should do it in O(n)
You can improve this solution by keeping a count of length of the list and stop comparisons after you have reached half the list.
This won't work if the number of characters in the string is greater than the maximum allowed stack depth. In this case, changing the list will work as follows...
Find out the length of the list.
once u reach the middle,
您可以使用随机化在 O(n) 时间和 O(1) 空间内完成此操作。
步骤1:计算字符串的哈希值,例如整个字符串的指纹。
步骤2:反转链表。
步骤 3:计算反转字符串的哈希值。
第四步:将链表反转到原来的顺序。
反转链表可以在 O(n) 时间和 O(1) 空间内完成,如下所示:
You can do it in O(n) time and O(1) space using randomization.
Step 1: Compute a hash of the string, such as a fingerprint of the whole string.
Step 2: Reverse the linked list.
Step 3: Compute a hash of the reversed string.
Step 4: Reverse the linked list to its original order.
Reversing a linked list can be done in O(n) time and O(1) space as follows:
遍历列表一次以找出其长度
,然后您可以检查字符 i == 字符长度 - i(i=0 到 length/2)是否
在 O(n^2) 时间内运行并使用 O(1) 存储
go through the list once to find out its length
then you can check whether character i == character length - i for i=0 to length/2
runs in O(n^2) time and uses O(1) storage
这是一个暴力算法,希望你能明白。
虽然 iterator_that_points_to 的代码(请原谅我的糟糕命名)是:
This is a brute-force algorithm, hope you get the idea.
While the code for iterator_that_points_to (bear with me for the poor naming) is:
根据他们告诉您的要求,这是他们想要的解决方案。
1)找到列表的中点。您可以通过使用两个指针并增加两个节点,然后将第二个节点增加一个节点来完成此操作。当第一个指针到达末尾时,第二个指针将位于列表的中间节点。
2)将链表从中间翻转到末尾。您可以在线性时间内完成此操作。
3) 现在比较两个列表。
4) 通过再次反转来恢复之前反转的列表。
最好的想法是编写一个函数来在线性时间内反转列表,并将其用作 ispalindrome 函数的助手。这可以清理代码并使其更容易在白板上进行管理。
Based on the requirements they told you here's the solution they want.
1) Find midpoint of list. You can do this by using two pointers and incrementing two nodes and the second by one node. Your second pointer will be at the middle node of the list when the first pointer reaches the end.
2) Reverse the linked list from the middle to the end. You can do this in linear time.
3) Now compare the two lists.
4) Restore the previously reversed list by reversing it again.
Best idea is to write a function to reverse the list in linear time and use it as a helper to the ispalindrome function. This cleans up the code and makes it easier to manage on a whiteboard.
也许您可以采取分而治之的解决方案:
O(n)
O(n)
比较 A 是否是 B 的逆:
如果剩余长度大于
一些常量,将 A 拆分为游标
A1和A2通过遍历,同样操作
对于 B1 和 B2 -
O(n)
;比较A1和B2,A2和B1同理
如果剩余长度小于
一些恒定的,只是蛮力
比较它们 - 将 B 复制到数组中
并向后阅读比较
与 A -
O(1)
请注意,步骤 3 应重复
O(logn)
次,因此,解决方案的复杂度为O(nlogn)< /代码>。
更详细的复杂性分析:
使用代换 (
n = 2^m
,f(2^m) = g(m)
) 来求解该方程。此递归的解决方案应该产生与 n*logn 相同复杂度类别的结果。由于递归调用,空间复杂度为
O(logn)
,但这似乎并没有违反任何约束。但是可以修改解决方案,使其不使用递归调用,而是使用循环 - 您应该只存储递归深度和该深度的位置(想象一下您绘制了递归树 - 您只需要 2 个整数来存储位置在那棵树上知道你的下一步是什么)。Maybe you could do a divide and conquer solution:
O(n)
O(n)
compare if A is the reverse of B:
if length left is greater than
some constant, split A into cursors
A1 and A2 by traversing, do the same
for B1 and B2 -
O(n)
; compare A1 andB2, and A2 and B1 in the same way
if length left is smaller than
some constant, just brute force
compare them - copy B into an array
and read it backwards comparing it
with A -
O(1)
Note that step 3 should be repeated
O(logn)
times, therefore, the complexity of the solution isO(nlogn)
.Complexity analysis in more detail:
Use substitution (
n = 2^m
,f(2^m) = g(m)
) to solve this equation. Solution of this recursion should yield something in the same complexity class as n*logn.Space complexity is
O(logn)
because of recursive calls, but that does not seem to be violating any constraints. But the solution could be modified so that it doesn't use recursive calls, but a loop instead - you should only store recursion depth and position at that depth (imagine you have the recursion tree drawn - you simply need 2 integers to store the position in that tree to know what your next step is).这个看起来很酷。
假设您有一个链接列表 Node1->Node2->Node3->--->Noden。
让 sum1=sum2=0
你所要做的就是遍历一次列表并计算
并比较它们是否相等
if equal
else
时间复杂度:O(n)
空间复杂度:O(1)
This one look cool .
Say suppose you have a link-list Node1->Node2->Node3->--->Noden.
let sum1=sum2=0
all you have to do is traverse the list once and compute
and compare whether they are equal
if equal
else
Time complexity :O(n)
Space complexity:O(1)