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

相关推荐
帅帅爱数学29 分钟前
DeepMimic论文详细解析:基于示例引导的深度强化学习实现物理仿真角色技能
算法·强化学习
Dream it possible!1 小时前
LeetCode 面试经典 150_哈希表_快乐数(45_202_C++_简单)(哈希表;快慢指针)
leetcode·面试·散列表
IT成长日记1 小时前
【LVS入门宝典】LVS调度算法轮询(RR)深度解析:从原理到实战的公平调度之道
算法·lvs·rr·轮询调度算法
NAGNIP1 小时前
一文搞懂量化、剪枝和知识蒸馏都是什么?
算法
点云SLAM2 小时前
GTSAM 中自定义因子(Custom Factor)的详解和实战示例
算法·机器人·slam·后端优化·gtsam·gtsam自定义因子·因子图
萘柰奈2 小时前
LeetCode刷题记录----62.不同路径(Medium)
算法·leetcode·职场和发展
阳光明媚sunny3 小时前
爬楼梯算法java实现
算法·动态规划
贝塔实验室3 小时前
LDPC码的概念
科技·学习·程序人生·算法·学习方法·程序员创富·改行学it
weixin_307779133 小时前
矩形势阱(V(x) = -H for |x|≤L)的束缚态能级求解与宇称分类
算法
MMjeaty4 小时前
数据结构——栈和队列
数据结构·算法