为什么力扣解题时,通常使用指针+new 创建类对象?

0 阅读3分钟

核心原因:力扣场景下对象需要持久化

为什么指针+new可以实现持久化

指针+new其实创建的是堆对象!

特性栈对象 (Stack Object)堆对象 (Heap Object)
创建方式直接声明(如 Person p;),自动分配用 new/make_unique/make_shared 创建,手动分配
内存管理编译器自动分配 / 释放,无需手动干预需手动释放(delete),或依赖智能指针自动释放
生命周期随作用域结束销毁(如函数执行完、代码块结束)直到手动释放(delete)或程序结束才销毁
内存大小栈空间小(通常几 MB),易栈溢出堆空间大(接近系统可用内存),适合大对象
访问方式直接通过对象名访问(. 运算符)通过指针访问(-> 运算符)
灵活性固定大小,创建后不可调整动态分配,大小可灵活调整(如动态数组)

为什么力扣中需要持久化?

算法逻辑需要「跨作用域操作同一个对象」

核心操作对象需要在多个函数 / 代码逻辑中被持续访问和修改,而不是局限在某个临时作用域里。

// 创建栈节点并让外部指针指向它
void createStackNode(ListNode*& head) {
    ListNode node(10)// 栈对象:仅在当前函数作用域有效 
    head = &node;  // 让外部指针指向栈对象 
    cout << "函数内访问:" << head->val <<"\n";
} 
int main() {
    ListNode* head = nullptr;
    createStackNode(head); // 函数执行完,栈对象已销毁,后续访问=野指针 
    if (head) cout << head->val << "\n"// 无效内存,结果乱码/崩溃 
    return 0;
}
数据结构的「链式引用」依赖持久化

链表、二叉树的核心是「指针引用关系」:比如链表节点的next、树节点的left/right,这些指针需要指向稳定存在的对象

如果用栈对象:

  • 每个节点都是临时的,作用域结束就销毁;
  • 指针引用的是 “消失的对象”,整个数据结构就成了 “空中楼阁”。

如果用堆对象:

  • 每个节点都持久化存在;
  • 指针可以安全地指向其他节点,形成稳定的链式结构(比如node1->next = node2),这是链表 / 树能正常工作的基础。
力扣的判题机制要求对象「全程有效」
void createNode(ListNode*& head, int val) {
    ListNode* node = new ListNode(val); // 堆对象,持久化存在
    head = node; // head指向堆对象,函数结束后对象仍在
}

int main() {
    ListNode* head = nullptr;
    createNode(head, 1); // 函数执行完,堆对象还在
    traverse(head);      // 正常访问,输出1
    return 0;
}

力扣的判题系统会调用你写的函数(比如createNode),并在函数执行完后,遍历你返回的链表 / 树来验证结果

如果你的对象没有持久化,判题系统遍历的时候就会访问到无效内存,直接判定你的代码错误。

你的代码不仅要 “执行完”,还要让返回的对象在判题系统检查时依然有效,这必须依赖堆对象的持久化特性。