LeetCode单向链表回文判定心得

1.分析题目

  原题目:Given a singly linked list, determine if it is a palindrome.

  题意非常明确,即判断一个单项链表是否为回文。比如像“1 2 3 2 1”、 “1 2 2 1”为回文;而“1 2 3 4”、 “1 2 2 3”均不是回文。


2.寻找题目切入点

  2-1:考虑特殊案例

  在理解题意后,我们普遍都可以想出大致的思路。但是一般在下手之前,我们需要先多考虑些“特别的输入”。这样做,一来我们能够保障程序的准确性,二来我们有时能够大幅降低debug耗时(有时候案例过不去往往在于忽略了边界输入)。

  所以,在本题中,主要有两种特殊输入。一是空表, 二是长度为1的链表。在我们编写solution时,我们可以先把特殊情况放在最前面。代码如图所示:

//先考虑特殊案例
        //特例1:空链表
        if(head == NULL){
            return true;
        }
        //特例2:长度为1的链表
        if (head->next == NULL) {
            return true;
        }


  2-2: 算法的优化

  其实本题目有许多算法可用,毕竟题意是归类为“Easy”难度。

  最简单的想法是我们可以把链表一次遍历过去后存入一个数组(或者是栈),然后通过对数组的操作进行判断。这种方法投机取巧地避免了单项链表只能单向遍历的局限。然而这浪费了空间,此方法空间复杂的为O(n)。

  而原题的follow up要求我们空间复杂度为O(1),因此上述方案不够精简。

  那么我们可否节省空间呢?答案是显然的。

  为了使得空间复杂度为O(1),我们必须要在遍历链表的时候同时完成判断。然而我们的链表是单向的,那么该如何做呢?

  也许有些人对单向的理解就是链表只能向一个方向遍历,但事实并非那么局限,单向应该意味“每个节点只有一个后继节点”。所以,我们可以考虑,将后半部分的节点的next指向前一个节点,使得单向链表变为半个“双向链表”。

  比如对于“1 2 3 2 1”, 我们访问只能从1访问到5,即 1 -> 2 -> 3 -> 2 -> 1。 而根据上面的思路,我们可以将其变为:1 -> 2 -> 3  2 <- 1(我们只需考虑后面length / 2 个节点的方向改变即可)

  大体实现可以分为四步:

  1. 遍历列表求得链表长度,获取尾节点

        //遍历链表以便确定总长度
        CurrentNode = head;
        while (CurrentNode != NULL) {
            ListLength++;
            //记录尾节点
            if (CurrentNode->next == NULL) {
                Tail = CurrentNode;
            }
            
            CurrentNode = CurrentNode->next;
        }

  2.遍历链表获得中间节点地址  

 Middle = ListLength / 2 + 1;
        int i = 1;
        MiddleNode = head;
        //寻找中间节点
        while (i != Middle) {
            MiddleNode = MiddleNode->next;
            i++;
        }

  3.遍历中间节点以后的节点以便改变next方向

//改变从中间开始的节点next指针,使其反向链接
        CurrentNode = MiddleNode;
        PreviousNode = MiddleNode;
        while (CurrentNode != NULL) {
            TempNode = CurrentNode->next;
            CurrentNode->next = PreviousNode;
            PreviousNode = CurrentNode;
            CurrentNode = TempNode;
            
        }

  4.从链表两端向中间遍历以判断回文

  //从链表两端向中间遍历节点
        i = 1;
        CurrentNode = head;
        CurrentNode2 = Tail;
        while (i <= ListLength / 2) {
            //寻找到不匹配点直接返回false
            if (CurrentNode->val != CurrentNode2->val) {
                return false;
            }
            CurrentNode = CurrentNode->next;
            CurrentNode2 = CurrentNode2->next;
            i++;
        }

3.题目收获

  1.我们在下手之前需要养成“特殊输入优先”的习惯,一来保证程序的正确性,二来降低调试耗时。

  2.对于算法的优化,我们可以通过“是否做了重复性工作”的思想来降低时间复杂度和空间复杂度,从而对算法进行优化。

  3.对于对象中只需内部需要的变(常)量,我们可以列为private,避免外部意外访问。如图所示:

private:
    int ListLength = 0;//记录链表长度
    ListNode *CurrentNode;//记录当前指针
    ListNode *CurrentNode2;//记录当前指针
    ListNode *MiddleNode;//若长度为奇数,则为正中间节点;若为偶数,则为第n/2+1个节点
    ListNode *TempNode;//以便反向链接用
    ListNode *PreviousNode;//以便反向链表使用
    ListNode *Tail;//记录尾节点
    int Middle;//以便记录中央节点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,有三种方法可以解决LeetCode上的最长回文子串问题。 方法一是使用扩展中心法优化,即从左向右遍历字符串,找到连续相同字符组成的子串作为扩展中心,然后从该中心向左右扩展,找到最长的回文子串。这个方法的时间复杂度为O(n²)。\[1\] 方法二是直接循环字符串,判断子串是否是回文子串,然后得到最长回文子串。这个方法的时间复杂度为O(n³),效率较低。\[2\] 方法三是双层for循环遍历所有子串可能,然后再对比是否反向和正向是一样的。这个方法的时间复杂度也为O(n³),效率较低。\[3\] 综上所述,方法一是解决LeetCode最长回文子串问题的最优解法。 #### 引用[.reference_title] - *1* [LeetCode_5_最长回文子串](https://blog.csdn.net/qq_38975553/article/details/109222153)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Leetcode-最长回文子串](https://blog.csdn.net/duffon_ze/article/details/86691293)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [LeetCode 第5题:最长回文子串(Python3解法)](https://blog.csdn.net/weixin_43490422/article/details/126479629)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值