leetcode_234 回文链表

1. 题意

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

2. 题解

2.1 链表转数组

链表不好操作,直接把链表中的数给放进数组里面。

数组里面相向双指针就可以解决了。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        
        vector<int> a{};

        while ( head ) {
            a.push_back( head->val );
            head = head->next;
        }

        int l = 0;
        int r = static_cast<int>(a.size()) - 1;

        while ( l < r) {
            if ( a[l] != a[r] )
                return false;
            l++;
            r--;
        }

        return true;
    }
};
2.2 栈反转

可以遍历链表一遍把值放入栈中,再依次出栈就是逆序输出了。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:

    bool isPalindrome(ListNode* head) {
        stack<int> st;
        auto cur = head;
        for ( ;cur;cur=cur->next) {
            st.push(cur->val);
        }

        while (head) {
            if (head->val != st.top())
                return false;
            st.pop();
            head = head->next;
        }

        return true;
    }
};
2.3 尾递归+变量标记

其实这种方法跟栈的做法本质是一样的。

只是变得更加不好理解了。。。

你让我下次写,我不一定能写出来。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    bool get_ans(ListNode *head, ListNode * &pre) {
        if ( head != nullptr ) {
            bool res = get_ans(head->next, pre);
            
            if ( res == false )
                return false;
            
            if ( pre->val != head->val)
                return false;
            
            pre = pre->next;
        }
        return true;
    }

    bool isPalindrome(ListNode* head) {
        
        ListNode *&lp = head;
        return get_ans( head, lp);
    }
};
2.4 反转后半部分链表比较

这种做法虽然复杂,但是很有价值。

找到链表的中间位置是leetcode-876. 链表的中间结点

反转后半部分链表是leetcod-206. 反转链表

可以先通过快慢指针找到后半部分链表的前驱节点,

进而再找到后半部分链表的头节点。

再比较的时候,我们可以用右半部分遍历完成作为循环条件,

因为这样不需要处理链表节点数为奇数的情况。

前后部分的链不需要断,我们只需要反转一次后半部分进行比较后。

再反转恢复回去就行了。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:

    ListNode *get_mid(ListNode *head) {
        if (head == nullptr)
            return nullptr;
        auto slow = head;
        auto fast = head->next;

        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
        }

        return slow;
    }

    ListNode *reverse_list(ListNode *head) {

        ListNode *nHead{};

        auto cur = head;
        while ( cur ) { 
            auto nxt = cur->next;
            cur->next = nHead;
            nHead     = cur;

            cur = nxt;
        }
        return nHead;
    }

    // void dump_list(ListNode *head) {
    //     while ( head ) {
    //         cout << head->val << " ";
    //         head = head->next;
    //     }
    //     cout << "\n";
    // }

    bool isPalindrome(ListNode* head) {
        
        auto pre_r = get_mid( head );
        auto nHead = reverse_list( pre_r->next );

        auto lp = head;
        auto rp = nHead;

        bool ans{ true };
        while ( rp ) {
            if ( lp->val != rp->val ) {
                ans = false;
                break;
            }
            lp = lp -> next;
            rp = rp -> next;
        }

        reverse_list( nHead );

        // dump_list( head );

        return ans;
    }
};

当然你要非要写左半部分遍历作为条件也不是不可以,

需要额外处理一些东西,包括左右部分链表的断链与恢复,

还有奇数情况的特殊处理,如何判断节点数是奇数呢?

fast指针值为空。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:

    ListNode * reverseList(ListNode *head) {

        ListNode *nHead = nullptr;
        auto cur = head;

        while ( cur ) {
            auto nxt  = cur->next;
            cur->next = nHead;
            nHead     = cur;

            cur = nxt;
        }

        return nHead;
    }
    void dump_list(const ListNode *head){
        const ListNode *cur = head;

        while (cur != nullptr) {
            cout << cur->val << " ";
            cur = cur->next;
        }
        cout << "\n";
    }


    bool isPalindrome(ListNode* head) {
        if ( head == nullptr || head->next == nullptr )
            return true;

        auto slow = head;
        auto fast = head->next;

        while ( fast && fast->next ) {
            slow = slow->next;
            fast = fast->next->next;
        }

        auto lp = head;
        auto nrHead = reverseList( slow->next );
        auto rp = nrHead;
        slow->next = nullptr;

        auto lend = slow; 
        if ( fast != nullptr )
            lend = nullptr;

        bool res{true};
        while ( lp != lend ) {
            if ( lp->val != rp->val ) {
                res = false;
                break;
            }
            lp = lp->next;
            rp = rp->next;
        }
        slow->next = reverseList( nrHead );

        return res;
    }
};

3. 参考

leetcode
0x3f

相关推荐
晓13131 天前
第二章 【C语言篇:入门】 C 语言基础入门
c语言·算法
yong99901 天前
MATLAB面波频散曲线反演程序
开发语言·算法·matlab
JicasdC123asd1 天前
【工业检测】基于YOLO13-C3k2-EIEM的铸造缺陷检测与分类系统_1
人工智能·算法·分类
Not Dr.Wang4221 天前
自动控制系统稳定性研究及判据分析
算法
VT.馒头1 天前
【力扣】2722. 根据 ID 合并两个数组
javascript·算法·leetcode·职场和发展·typescript
ffqws_1 天前
A*算法:P5507 机关 题解
算法
执着2591 天前
力扣hot100 - 108、将有序数组转换为二叉搜索树
算法·leetcode·职场和发展
2501_901147831 天前
学习笔记:单调递增数字求解的迭代优化与工程实践
linux·服务器·笔记·学习·算法
AI科技星1 天前
张祥前统一场论核心场方程的经典验证-基于电子与质子的求导溯源及力的精确计算
线性代数·算法·机器学习·矩阵·概率论
kebijuelun1 天前
ERNIE 5.0:统一自回归多模态与弹性训练
人工智能·算法·语言模型·transformer