题目来源于力扣–https://leetcode-cn.com/leetbook/read/top-interview-questions-easy/xnv1oc/
1、首先最容易想到的是复制一个新的链表,然后将新链表反转,然后与原链表比较,相等的话就是回文链表,否则就不是。但是效率比较低,也占用了一部分新的空间。下面直接看代码:
#include<stdio.h>
#include<stdlib.h>
bool isPalindrome(struct ListNode* head);
struct ListNode* reverseList(struct ListNode* head);
struct ListNode* copyList(struct ListNode* head);
struct ListNode {
int val;
struct ListNode *next;
};
int main(){
// 动态申请空间
struct ListNode *lnode1 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *lnode2 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *lnode3 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *lnode4 = (struct ListNode *)malloc(sizeof(struct ListNode));
// 初始化链表
lnode1->val = 1;
lnode2->val = 2;
lnode3->val = 2;
lnode4->val = 1;
lnode1->next = lnode2;
lnode2->next = lnode3;
lnode3->next = lnode4;
lnode4->next = NULL;
// 调用函数
bool isTrue = isPalindrome(lnode1);
printf("%d",isTrue);
return 0;
}
bool isPalindrome(struct ListNode* head){
// 调用copy函数
struct ListNode *newHead = copyList(head);
// 调用反转函数
struct ListNode *reverseHead = reverseList(newHead);
// 判断反转的链表与原链表是否一致
while(head!=NULL){
// 如果有一个不一样就不是
if(head->val!=reverseHead->val){
return false;
}
// 指针后移
head = head->next;
reverseHead = reverseHead->next;
}
return true;
}
// 递归反转列表
struct ListNode* reverseList(struct ListNode* head){
//递归结束条件
if(head==NULL||head->next==NULL){
return head;
}
// 调用函数本身
struct ListNode* newHead = reverseList(head->next);
// 反转节点
head->next->next = head;
// 尾节点置NULL
head->next = NULL;
// 返回上一层
return newHead;
}
// copy一个新的链表
struct ListNode* copyList(struct ListNode* head){
// copy一个新的链表
struct ListNode *p = head;
struct ListNode *newHead = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *q = newHead;
// 将第一个结点的值给新的结点
q->val = p->val;
q->next = NULL;
p = p->next;
// 动态申请结点将原链表的结点copy到新的链表上
while(p!=NULL){
// 申请新的结点
struct ListNode *lnode = (struct ListNode *)malloc(sizeof(struct ListNode));
// 结点赋值,尾插法
lnode->val = p->val;
// 尾结点指针置空
lnode->next = NULL;
// 连接到新的链表上
q->next = lnode;
// q指到尾结点
q = q->next;
// 原链表指针后移,进行下一个结点操作
p = p->next;
}
return newHead;
}
2、还有一种方法就是,反转链表的一半,然后和另一半比较,看看是不是一致,一致的话就是回文否则不是。节省了空间,效率也提高了。这个判断奇数偶数,注释标记出来了。
#include<stdio.h>
#include<stdlib.h>
bool isPalindrome(struct ListNode* head);
struct ListNode* reverseList(struct ListNode* head);
struct ListNode* copyList(struct ListNode* head);
struct ListNode {
int val;
struct ListNode *next;
};
int main(){
// 动态申请空间
struct ListNode *lnode1 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *lnode2 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *lnode3 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *lnode4 = (struct ListNode *)malloc(sizeof(struct ListNode));
// 初始化链表
lnode1->val = 1;
lnode2->val = 2;
lnode3->val = 2;
lnode4->val = 1;
lnode1->next = lnode2;
lnode2->next = lnode3;
lnode3->next = lnode4;
lnode4->next = NULL;
// 调用函数
bool isTrue = isPalindrome(lnode1);
printf("%d",isTrue);
return 0;
}
bool isPalindrome(struct ListNode* head){
// 快指针
struct ListNode *p;
// 慢指针
struct ListNode *q;
p = head;
q = head;
// p初始化在头结点,p每次走两步,表明走一次就是奇数个结点,走到最后p不为空表示为链表个数为奇数,p为空表示偶数
while(p!=NULL&&p->next!=NULL){
p = p->next->next;
q = q->next;
}
// p不为空,表示奇数,q指针往后移一个,后边的才是需要反转的。
if(p!=NULL){
q = q->next;
}
// 反转后边的链表
q = reverseList(q);
// 判断后半边与前半边是否一致
while(q!=NULL){
// 如果有一个不一样就不是
if(head->val!=q->val){
return false;
}
// 指针后移
head = head->next;
q = q->next;
}
return true;
}
// 递归反转列表
struct ListNode* reverseList(struct ListNode* head){
//递归结束条件
if(head==NULL||head->next==NULL){
return head;
}
// 调用函数本身
struct ListNode* newHead = reverseList(head->next);
// 反转节点
head->next->next = head;
// 尾节点置NULL
head->next = NULL;
// 返回上一层
return newHead;
}