链表面试题6之回文结构

 经过前几道题的铺垫,那么我们也是来到了链表的第六关。这也是一道非常经典的题目。

目录

逆置法

数组法


那么对于这道题目,我们要判断回文结构,实际上就是判断链表对不对称。这种类型的题目我们好像在哪里见过,对了,就是在字符串那里。那这里咱们可不可以也用一个双指针法,然后一个从头遍历,一个从尾开始遍历??当然是不可以的,因为链表的物理结构就规定了,链表只能从头开始遍历。

那么我们想到这里的话,也自然会想到,我现在的难点是尾端无法向前遍历,有什么办法能让我从尾端向前面遍历呢?这我们就灵机一动,把链表部分逆置不就好了?

那么由此我们就能得出第一种方法

逆置法

思路:1.先找到中间节点,
2.从中间节点以后开始逆置
3.然后从中间节点向后迭代
4.如果是回文,返回true,否则返回false

那这里我把代码贴一下

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        ListNode* dummy = (ListNode*)malloc(sizeof(ListNode));//哨兵结点
        dummy->next = A;
        ListNode*fast = dummy;
        ListNode*slow = dummy;
        while(fast && fast->next)  //获取中间结点
        {
            fast = fast->next->next;
            slow = slow->next;
        }
         
        ListNode* cur = slow->next; //反转链表
        ListNode* next = cur->next;
        ListNode* pre = slow;
        slow->next = NULL; //防止形成环!!!!!
        while(1)
        {
            cur->next = pre;
            pre = cur;
            if(next == NULL) //注意判断的是next而不是cur->next
                break;
            cur = next;
            next = cur->next;
        }
         
        ListNode* head = A;
        ListNode* tail = cur;
        while(tail != slow)
        {
            if(head->val != tail->val)
                return false;
            tail = tail->next;
            head = head->next;
        }
        return true;
    }
};

当然,这里找中间节点涉及到一个快慢指针的问题。

数组法

没错,想到了逆置,我们在实现的过程中也会出现一个问题,那就是原链表和逆置后的链表的输出结果,需要我们去存储。那么这里我们就想,能不能用数组优化一下,使得我们不用两个链表的双线操作。

那么他来了!

思路:直接创建一个int a[900]的数组。储存输出的数据,再逆序访问输出比较。

这样真的可行吗???

注意,这里的空间复杂度已经是O(n)了,嗯?为什么是O(n)呢?我创建的数组空间不是有限个空间吗?没错,这里的空间复杂度就是O(1)。这种方法是可行的。那什么时候是O(n)呢?

我们在动态数组的时候就是O(n),是空间会随着你所给数据的多少而扩容不确定的才会是O(n)

 但是我这里已经明确给出了链表长度不超过900,而我不在乎空间的浪费,就定义为a[900]。这是常数,下面是两种情况会给出O(n)的空间。我

// 动态分配空间(与输入规模相关)
int* a = new int[n]; 

// 可变长度容器(隐式依赖输入规模)
std::vector<int> a(n); 

具体代码: 

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
};

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        int buffer[900]; 
        int length = 0;
        
        // 步骤1:存储链表数据到数组
        ListNode* curr = A;
        while (curr && length < 900) {
            buffer[length++] = curr->val;
            curr = curr->next;
        }
        
        // 步骤2:双指针回文校验
        int left = 0, right = length - 1;
        while (left < right) {
            if (buffer[left] != buffer[right]) {
                return false;
            }
            left++;
            right--;
        }
        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. **恢复链表(可选)** 如果需要保持原有链表不变,在最后应再次反转后半部分以还原整个链表状态。 --- ####
评论 22
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值