You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归判链表回文遇栈溢出,求Dart相关问题及最优解法

问题解答

1. 递归栈溢出的原因

你的递归代码存在两个核心问题:

  • 递归深度超标:每次递归都会处理链表的剩余部分,对于长度为n的链表,递归深度达到O(n)。当n足够大时(比如10^4级别),嵌套调用层数会超过Dart虚拟机的栈容量上限,直接触发栈溢出。
  • 逻辑错误:代码仅比较当前链表的头节点和尾节点,随后递归处理head.next,但并没有真正移除已比较过的尾节点——比如原链表是[1,2,2,1],第一次比较1和1后,递归处理[2,2,1],此时尾节点仍是1,和头节点2比较会直接返回false,逻辑完全错误。此外,每次递归都要遍历整个链表找尾节点,时间复杂度为O(n²),大测试用例不仅会栈溢出,还会超时。

2. Dart的递归深度查询

Dart没有固定的官方递归深度上限,该数值与运行环境(如Dart VM、Flutter、Web编译)相关,通常在几千到一万左右。你可以通过以下代码自行测试当前环境的上限:

int depth = 0;

void measureDepth() {
  depth++;
  measureDepth();
}

void main() {
  try {
    measureDepth();
  } catch (_) {
    print("当前环境递归深度上限: $depth");
  }
}

3. 更高效的解法(时间O(n),空间O(1))

最优解法是快慢指针+反转链表,无需额外存储整个链表,也不会出现栈溢出问题:
步骤:

  • 快慢指针找中间节点:慢指针每次走1步,快指针每次走2步,快指针走到末尾时,慢指针刚好处于链表中间位置。
  • 反转慢指针之后的后半部分链表。
  • 同时遍历前半部分和反转后的后半部分,逐一比较节点值。
  • (可选)将反转的后半部分转回原状态,恢复链表结构。

Dart代码实现:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *   int val;
 *   ListNode? next;
 *   ListNode([this.val = 0, this.next]);
 * }
 */
class Solution {
  bool isPalindrome(ListNode? head) {
    if (head == null || head.next == null) return true;
    
    // 1. 快慢指针找中间节点
    ListNode? slow = head;
    ListNode? fast = head;
    while (fast?.next != null && fast?.next?.next != null) {
      slow = slow?.next;
      fast = fast?.next?.next;
    }
    
    // 2. 反转后半部分链表
    ListNode? reversedHalf = reverseList(slow?.next);
    
    // 3. 比较前半部分和反转后的后半部分
    ListNode? p1 = head;
    ListNode? p2 = reversedHalf;
    bool isPalin = true;
    while (p2 != null) {
      if (p1?.val != p2.val) {
        isPalin = false;
        break;
      }
      p1 = p1?.next;
      p2 = p2.next;
    }
    
    // 4. (可选)恢复原链表
    slow?.next = reverseList(reversedHalf);
    
    return isPalin;
  }
  
  // 辅助函数:反转链表
  ListNode? reverseList(ListNode? head) {
    ListNode? prev = null;
    ListNode? current = head;
    while (current != null) {
      ListNode? nextTemp = current.next;
      current.next = prev;
      prev = current;
      current = nextTemp;
    }
    return prev;
  }
}

该方法时间复杂度为O(n),仅遍历链表三次(找中间、反转、比较),空间复杂度为O(1),完全适配所有测试用例。


内容的提问来源于stack exchange,提问作者tri-ethylEther

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 18:40:24