11.回文链表(两种方法)(双指针+头插)

本文详细介绍了如何通过双指针技巧和头插逆序法检查链表是否为回文。两种方法对比,助你理解链表回文判断核心逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面试题 02.06. 回文链表 试试这题

编写一个函数,检查输入的链表是否是回文的

示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true

思路:首先要得到链表的一半,然后将前半部分或后半部分的链表逆置,然后和前面的另一半比对,若相同则是回文的,反之则不是,细节请看代码

第一种方法:找中间结点+头插逆置
求出结点总个数然后即可以找到中间位置,这样效率不高,但是可以把链表的结构掌握的很清楚

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

typedef struct ListNode Node;
bool isPalindrome(struct ListNode* head){
    Node* cur = head;
    int cnt = 0;
    while(cur)
    {
        cur = cur->next;
        cnt++;
    }
    cur = head;//记得要将cur在返回head结点
    int jud = cnt % 2;//判断结点的个数是奇数还是偶数
    //定义一个number保留中间结点的位置
    int number = cnt = cnt / 2;
    while(number--)
    {
        cur = cur->next;
    }
    if(jud == 1)
        cur = cur->next;//如果是奇数个结点,那么就跳过中间结点
    //开始头插逆置
    Node* newhead = NULL;
    while(cnt--)
    {
        Node* next = cur->next;
        cur->next = newhead;
        newhead = cur;
        cur = next;
    }
    while(newhead && head)
    {
        if(head->val != newhead->val)
            return false;
        newhead = newhead->next;
        head = head->next;
    }
    return true;
}

第二种方法:双指针+头插逆序
利用fast指针和slpw指针,fast指针每次做两步,slow指针每次走一步,然后两个指针同时遍历链表,当fast指针走完链表的时候,这时slow指针只走了链表的一半,这就是上面的优化,后面的头插比对有一点点不一样,我会在代码中提示出来。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

typedef struct ListNode Node;
bool isPalindrome(struct ListNode* head){
    if(head == NULL || head->next == NULL)
        return true;
    Node* fast = head;
    Node* slow = head;
    Node* prev = head;//保留链表的中间结点的上一个结点,为了让两个链表分开
    //因为节点数可能是奇数可能是偶数,所以要用fast(偶数)fast->next(奇数)判断
    while(fast && fast->next)
    {
        prev = slow;
        fast = fast->next->next;
        slow = slow->next;
    }


    //将前半部分链表和后半部分分开,易错点
    prev->next = NULL;


    //头插后半段的链表
    Node* newhead = NULL;
    while(slow)
    {
        Node* next = slow->next;
        slow->next = newhead;
        newhead = slow;
        slow = next;
    }
    //比对两个链表,但是要注意如果节点数是奇数的话,两个链表的节点数不相同,所以判断的时候要以,前半部分的结束为结束
    while(head)
    {
        if(head->val != newhead->val)
            return false;
        head = head->next;
        newhead = newhead->next;
    }
    return true;
}
### 如何在 Visual Studio 中实现回文链表问题 要在 Visual Studio 中实现面试题 02.06 回文链表的解决方案,可以按照以下方式编写代码并运行程序。以下是基于 C++ 实现的一个完整方案。 #### 解决方案描述 该问题的核心在于验证单向链表是否为回文结构。可以通过反转链表的一部分并与原链表对比来完成这一目标[^1]。另一种常见方法是利用辅助数据结构(如栈),通过存储节点值再逐一比较的方式解决问题[^4]。 下面是一个完整的 C++ 实现: ```cpp #include <iostream> using namespace std; // 定义链表节点结构体 struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} }; class Solution { public: bool isPalindrome(ListNode* head) { if (head == nullptr || head->next == nullptr) return true; // 找到中间节点 ListNode *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } // 反转后半部分链表 ListNode *prev = nullptr, *curr = slow, *nextNode = nullptr; while (curr) { nextNode = curr->next; curr->next = prev; prev = curr; curr = nextNode; } // 对比前半部分和反转后的后半部分 ListNode *firstHalf = head, *secondHalf = prev; while (secondHalf) { if (firstHalf->val != secondHalf->val) return false; firstHalf = firstHalf->next; secondHalf = secondHalf->next; } return true; } }; // 辅助函数:创建链表 ListNode* createList(const vector<int>& nums) { if (nums.empty()) return nullptr; ListNode dummy(0); ListNode* tail = &dummy; for (const auto& num : nums) { tail->next = new ListNode(num); tail = tail->next; } return dummy.next; } // 主函数测试 int main() { vector<int> input = {1, 2, 3, 2, 1}; // 测试输入 ListNode* head = createList(input); Solution solution; cout << (solution.isPalindrome(head) ? "True" : "False") << endl; system("pause"); return 0; } ``` #### 关键点解析 1. **寻找中间节点** 使用快慢指针法找到链表的中间位置。`slow` 指针每次移动一步,而 `fast` 每次移动两步。当 `fast` 到达链表末尾时,`slow` 正好位于中间位置。 2. **反转后半部分链表** 将链表的后半部分就地反转以便于后续比较。此过程不需额外空间开销。 3. **逐一对比前后两部分** 比较原始链表的前半部分与反转后的后半部分是否一致。如果存在差异则返回 `false`;否则继续直到结束。 4. **恢复链表(可选)** 如果需要保持原有链表不变,在最后应再次反转后半部分以还原整个链表状态。 --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hyzhang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值