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

相关推荐
渡之4 分钟前
GRiM-Net 深度解析 | 无人机 GNSS 拒止场景下两阶段跨视角视觉定位框架
深度学习·算法·动态规划·无人机
测试仪器廖生1359025638523 分钟前
罗德与施瓦茨 FSP13频谱分析仪FSP30
网络·人工智能·算法
happymaker062626 分钟前
LeetCodeHot100——560.和为K的子数组
算法
dtq042443 分钟前
C语言刷题数组5,6(求平均值,求最大值)
c语言·数据结构·算法
郭梧悠1 小时前
Hash算法入门Hash冲突解决方案
算法·哈希算法
洛水水2 小时前
【力扣100题】81.寻找两个正序数组的中位数
数据结构·算法·leetcode
happymaker06262 小时前
LeetCodeHot100——155.最小栈
算法
洛水水2 小时前
【力扣100题】85.每日温度
算法·leetcode·职场和发展
Coder-magician2 小时前
《代码随想录》刷题打卡day15:二叉树part05
数据结构·c++·算法
Kurisu_红莉栖2 小时前
力扣56合并区间
算法·leetcode