单链表面试题

发布于 2024-10-03 02:05:47 字数 293 浏览 4 评论 0原文

假设我们有一个字符串: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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

烧了回忆取暖 2024-10-10 02:05:47

我的解决方案:采用快速和慢速指针,反转列表的一半并与另一半进行比较。并将反转的一半反转,以便列表看起来像原始列表。我正在寻找更好的解决方案。

编辑:因为我找不到更好的溶胶。

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.

撧情箌佬 2024-10-10 02:05:47

下面应该在 O(n) 内完成

  1. 递归到列表末尾,保留头指针。
  2. 当退出递归循环时,将当前与头部进行比较,并将头部移动到 head.next ,直到用完字符或发现不匹配。

您可以通过记录列表的长度并在达到列表的一半后停止比较来改进此解决方案。

如果字符串中的字符数大于允许的最大堆栈深度,则此操作将不起作用。在这种情况下,更改列表将按如下方式进行...

找出列表的长度。

  • 不断反转链接列表中的链接,直到到达中间......
    一旦你到达中间,
  • 你将有一半的列表指向开始,其余的将指向结束。
  • 运行 while 循环直到最后并比较相应的字符并再次反转链接......

The following should do it in O(n)

  1. Recurse to the end of the list, preserve the head pointer.
  2. While coming out of the recursive loop, compare the current with the head and move the head to head.next until u run out of characters or find a mismatch.

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.

  • Keep reversing the links in the linked list as you go until you reach the middle....
    once u reach the middle,
  • You will have half the list pointing towards the start, the rest will be pointing towards the end.
  • Run a while loop till the end and compare corresponding characters and reversing the links again...
心不设防 2024-10-10 02:05:47

您可以使用随机化在 O(n) 时间和 O(1) 空间内完成此操作。

步骤1:计算字符串的哈希值,例如整个字符串的指纹。

步骤2:反转链表。

步骤 3:计算反转字符串的哈希值。

第四步:将链表反转到原来的顺序。

反转链表可以在 O(n) 时间和 O(1) 空间内完成,如下所示:

rev(head) {
  prev = nil;
  curr = head;
  next = head.next;
  while (curr != nil) {
    curr.next = prev;
    prev = curr;
    curr = next;
    next = curr.next;
  }
}

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:

rev(head) {
  prev = nil;
  curr = head;
  next = head.next;
  while (curr != nil) {
    curr.next = prev;
    prev = curr;
    curr = next;
    next = curr.next;
  }
}
淡淡の花香 2024-10-10 02:05:47

遍历列表一次以找出其长度

,然后您可以检查字符 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

羁拥 2024-10-10 02:05:47

这是一个暴力算法,希望你能明白。

<pseudocode>

begin = list.begin();
end = list.end();

while (begin < end) {
   previous = iterator_that_points_to(list, end);
   if (*begin != *previous)
      return false;

   begin++;
   end = previous;
}
return true;

</pseudocode>

虽然 iterator_that_points_to 的代码(请原谅我的糟糕命名)是:

Node* iterator_that_points_to(CharList const& theList, Node* to_find)
{
   Node* iterator = theList.rootNode;
   while (iterator.next != 0) {
      if (iterator.next == to_find)
         return iterator;

      iterator = iterator->next; 
   }
   return 0; // should never happen
}

This is a brute-force algorithm, hope you get the idea.

<pseudocode>

begin = list.begin();
end = list.end();

while (begin < end) {
   previous = iterator_that_points_to(list, end);
   if (*begin != *previous)
      return false;

   begin++;
   end = previous;
}
return true;

</pseudocode>

While the code for iterator_that_points_to (bear with me for the poor naming) is:

Node* iterator_that_points_to(CharList const& theList, Node* to_find)
{
   Node* iterator = theList.rootNode;
   while (iterator.next != 0) {
      if (iterator.next == to_find)
         return iterator;

      iterator = iterator->next; 
   }
   return 0; // should never happen
}

初相遇 2024-10-10 02:05:47

根据他们告诉您的要求,这是他们想要的解决方案。

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.

落墨 2024-10-10 02:05:47

也许您可以采取分而治之的解决方案:

  1. 遍历列表一次以确定其长度 - O(n)
  2. 再次遍历列表以将光标定位在一半上 - 您现在有光标 A & ; B - O(n)
  3. 比较 A 是否是 B 的逆:

    • 如果剩余长度大于
      一些常量,将 A 拆分为游标
      A1和A2通过遍历,同样操作
      对于 B1 和 B2 - O(n);比较A1和
      B2,A2和B1同理

    • 如果剩余长度小于
      一些恒定的,只是蛮力
      比较它们 - 将 B 复制到数组中
      并向后阅读比较
      与 A - O(1)

请注意,步骤 3 应重复 O(logn) 次,因此,解决方案的复杂度为 O(nlogn)< /代码>。

更详细的复杂性分析:

f(const) = const

f(n) = f(n/2) + f(n/2) + C*n

使用代换 (n = 2^m, f(2^m) = g(m)) 来求解该方程。此递归的解决方案应该产生与 n*logn 相同复杂度类别的结果。

由于递归调用,空间复杂度为 O(logn),但这似乎并没有违反任何约束。但是可以修改解决方案,使其不使用递归调用,而是使用循环 - 您应该只存储递归深度和该深度的位置(想象一下您绘制了递归树 - 您只需要 2 个整数来存储位置在那棵树上知道你的下一步是什么)。

Maybe you could do a divide and conquer solution:

  1. go through the list once to establish its length - O(n)
  2. go through the list again to position a cursor on the half - you now have cursors A & B - O(n)
  3. 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 and
      B2, 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 is O(nlogn).

Complexity analysis in more detail:

f(const) = const

f(n) = f(n/2) + f(n/2) + C*n

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).

洋洋洒洒 2024-10-10 02:05:47

这个看起来很酷。

假设您有一个链接列表 Node1->Node2->Node3->--->Noden。

让 sum1=sum2=0

你所要做的就是遍历一次列表并计算

           sum1 = (sum1+Nodei->data)*2.

           sum2 += Nodei->data*2^i.

并比较它们是否相等

if equal

   palindrome 

else

   not a palindrome. 

时间复杂度: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

           sum1 = (sum1+Nodei->data)*2.

           sum2 += Nodei->data*2^i.

and compare whether they are equal

if equal

   palindrome 

else

   not a palindrome. 

Time complexity :O(n)

Space complexity:O(1)

合约呢 2024-10-10 02:05:47
palindrome = true; //assume initially that it is a palindrome
count = 1;
q = p; // use a temporary pointer for traversing to end
while (q->next) { q = q->next; count ++; } //count the number of elements in the list
do{
   if (p->data != q->data) {palindrome = false; break;}//compare first and last elements of the list under consideration
   p = p->next; count -  = 2; //consider a new linked list with the two end-points cut off
   q = p; for (j = 0; j < count; j++) q = q=>next; 
} while (count > 0);
palindrome = true; //assume initially that it is a palindrome
count = 1;
q = p; // use a temporary pointer for traversing to end
while (q->next) { q = q->next; count ++; } //count the number of elements in the list
do{
   if (p->data != q->data) {palindrome = false; break;}//compare first and last elements of the list under consideration
   p = p->next; count -  = 2; //consider a new linked list with the two end-points cut off
   q = p; for (j = 0; j < count; j++) q = q=>next; 
} while (count > 0);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文