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

相关推荐
野犬寒鸦5 小时前
力扣hot100:螺旋矩阵(边界压缩,方向模拟)(54)
java·数据结构·算法·leetcode
欧阳x天5 小时前
顺序表相关练习题
c语言·数据结构·算法
緈福的街口5 小时前
【leetcode】130. 被围绕的区域
算法·leetcode·职场和发展
THMAIL6 小时前
机器学习从入门到精通 - KNN与SVM实战指南:高维空间中的分类奥秘
人工智能·python·算法·机器学习·支持向量机·分类·逻辑回归
皆过客,揽星河6 小时前
c语言程序之魂——算法(练习题,流程图,程序源码)
c语言·算法·流程图·源码·辗转相除法·c语言程序设计
zc.ovo6 小时前
牛子图论1(二分图+连通性)
数据结构·c++·算法·深度优先·图论
丑小鸭是白天鹅6 小时前
嵌入式C语言之链表冒泡排序
c语言·开发语言·链表
通往曙光的路上6 小时前
JAVA 十二幕啦啦啦啦啦啦啦啊啦啦啦啦a
java·开发语言·算法
得物技术6 小时前
得物灵犀搜索推荐词分发平台演进3.0
算法·架构·排序算法