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

相关推荐
FMRbpm1 分钟前
树的练习6--------938.二叉搜索树的范围和
数据结构·c++·算法·leetcode·职场和发展·新手入门
wubba lubba dub dub75012 分钟前
第三十三周 学习周报
学习·算法·机器学习
C+-C资深大佬20 分钟前
C++数据类型
开发语言·c++·算法
多米Domi01136 分钟前
0x3f 第35天 电脑硬盘坏了 +二叉树直径,将有序数组转换为二叉搜索树
java·数据结构·python·算法·leetcode·链表
想逃离铁厂的老铁42 分钟前
Day45 >> 115、不同的子序列 + 583. 两个字符串的删除操作 + 72. 编辑距离
算法·leetcode
cyyt1 小时前
深度学习周报(1.12~1.18)
人工智能·算法·机器学习
范纹杉想快点毕业1 小时前
C语言核心机制全解:内存、地址、数组与指针,共计30000字
算法
Σίσυφος19001 小时前
RANSAC算法原理与应用
算法
我星期八休息2 小时前
MySQL数据可视化实战指南
数据库·人工智能·mysql·算法·信息可视化
程序员-King.2 小时前
day144—递归—平衡二叉树(LeetCode-110)
算法·leetcode·二叉树·递归