判断回文链表

题目来源于力扣–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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值