如何判断一个单向链表是否为回文链表(Palindrome Linked List)
题目:给定一个单向链表,判断它是不是回文链表(即从前往后读和从后往前读是一样的)。原题见下图,还要求了O(n)的时间复杂度O(1)的空间复杂度。
我的思考:
1,一看到这个题目,大脑马上想到的解决方案就是数组。遍历链表,用数组把数据存下来,然后再进行一次遍历,同时用数组反向地与之比较,这样就可以判断是否回文。这个方法时间复杂度是O(n),达到了要求,然而空间复杂度显然不满足要求。所以,开数组这一类的方法显然不是最佳的。
2,既然要满足O(1)的空间复杂度,我就想到了用一个变量来存储这些数据,恰好题目给出的数据也是整型。具体思路就是用一个long int:sum来存储这些数据,第一次遍历:第一个节点的数据乘1加到sum,第二个节点的数据乘2加到sum,第三个节点的数据乘3加到sum……;然后再反向进行第二次遍历,sum减去最后一个节点的数据和1的乘积,sum减去倒数第二个节点的数据和2的乘积……。只要看最后的sum是否为0就可以判断链表是否回文。当然,在第一次遍历的时候需要一边遍历一边逆置该链表,才能进行第二次遍历。贴上代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: bool isPalindrome(ListNode* head) { ListNode *point1, *point2, *point3; point3 = point2 = head; point1 = NULL; long int sum = 0; int n = 1; if(head == NULL || head->next == NULL return true; while(point3->next != NULL)//第一次遍历,取值并逆置 { sum += n*point3->val; n++; point3 = point3->next; point2->next = point1; point1 = point2; point2 = point3; } sum += n*point3->val; point2->next = point1; n = 1; while(point2 != NULL)//第二次遍历 { sum -= n*point2->val; n++; point2 = point2->next; } if(sum == 0) return true; else return false; } };
提交的结果显示这个方法在题目的条件范围内是可行的:
仔细一想,如果节点中的数据是字符,是浮点数怎么办?这时这个方法的局限性就显现出来了。
3,不能用一个整型来存储字符这类的信息,那只能直接比较节点里的信息了。怎么比较?我们知道回文链表的特点就是对称,那么要判断是否回文就可以用两个指针指向对称的节点,看里面的信息是否一样。即对称的位置是否有对称的信息。由于是单向链表,不能同时用两个指针从头尾向内部遍历取值比较。那么就考虑从链表中间开始,用两个指针向两头遍历取值比较,显然这也需要进行链表逆置。
具体的做法就是先遍历一次链表得到链表长度。然后第二次遍历到链表中间,并在遍历的时候进行逆置。然后两个指针分离,分别向两个端点移动,同时进行比较,数据相同则继续,数据不同则直接返回false。直到遍历完成,最后返回true。代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: bool isPalindrome(ListNode* head) { int lenth, i; ListNode *point1, *point2, *point3; point3 = point2 = head; point1 = NULL; lenth = 0; if(head == NULL || head->next == NULL) return true; while(point3 != NULL)//取得长度 { point3 = point3->next; lenth++; } for(i = 0;i < (lenth / 2);i++)//遍历到中间,并逆置 { point3 = point2->next; point2->next = point1; point1 = point2; point2 = point3; } if((lenth % 2) == 1) point3 = point3->next; while(point3 != NULL && point1 != NULL)//两个指针开始向两头移动,取值比较 { if(point3->val != point1->val) return false; point3 = point3->next; point1 = point1->next; } return true;//比较中没有发现不同值,则为回文链表 } };
最后的结果也证明这个方法是可行的:
比起上一种方法,这个方法没有存储信息的操作,所以不必担心用什么数据类型去存储,也不用担心数据的溢出,适用的范围当然也就更大。
若博文中有什么不正确的地方欢迎大家指正,谢谢~
- Overload和Override的区别?
- C题 - A+B for Input-Output Practice (II)
- linux whatis与whatis database 使用及查询方法(man使用实例)
- Android 横向二级ListView列表
- override
- lintcode:Merge Sorted Array
- eclipse部署上Tomcat后的clean和publish功能
- RAC日志路径汇总
- 嵌入式编程时注意的事项
- AI顶级会议列表 & ACL相关
- PostgreSQL数据库监控中的统计学 - 对象空间的数据分布图
- 一道题采用两种设计模式:对比策略模式和模版方法
- 利用PHP SOAP实现WEB SERVICE
- MSSQL纵列转横列
- linux 查看端口是否被占用
- 数据仓库与数据集市的概念区别
- 细致的学习了一遍Android Material Design,简单做下笔记
- 【LeetCode从零单刷】Find Peak Element
- git环境的搭建
- 100 js js解析url地址获取参数