Bootstrap

LeetCode 热题 100_回文链表(24_234_简单_C++)(哈希表)(单链表;将值复制到数组中后用双指针法;快慢指针寻找中间节点+反转链表)

题目描述:

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

输入输出样例:

示例 1:
请添加图片描述

输入:head = [1,2,2,1]
输出:true
示例 2:
请添加图片描述

输入:head = [1,2]
输出:false

提示:
链表中节点数目在范围[1, 105] 内
0 <= Node.val <= 9

进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

题解:

解题思路:

思路一(将值复制到数组中后用双指针法)
1、创建一个额外的数组,将链表中的值存入数组中,通过数组进行回文的判断。

2、复杂度分析:
① 时间复杂度:O(n),其中 n 指的是链表的元素个数。 遍历链表并将值复制到数组中,O(n)。双指针判断是否为回文,执行了 O(n/2) 次的判断,即 O(n)。总的时间复杂度:O(2n)=O(n)。

② 空间复杂度:O(n),其中 n 指的是链表的元素个数,我们使用了一个数组列表存放链表的元素值。

思路二(快慢指针寻找中间节点+反转链表):
1、我们可以找到中间结点,然后将后半部分链表反转,再通过比较前半部分和后半部分是否构成回文链表,最后将后半部分链表复原。

2、具体思路如下:
① 查找中间结点(使用快慢指针)。
② 通过查找的中间结点将后半部分链表反转。
③ 逐个比较前半部分和后半部分是否构成回文链表。
④ 将后半部分链表复原。

3、复杂度分析
① 时间复杂度:O(n),其中 n 是链表的长度(节点个数)。查找中间结点为O(n/2),将后半部分链表反转为O(n/2),逐个比较前半部分和后半部分是否构成回文链表为O(n/2), 将后半部分链表复原为O(n/2),所以总的时间复杂度为O(n)。

② 空间复杂度:O(1),对原链表进行操作,使用常熟个额外空间。

代码实现

代码实现(思路一(将值复制到数组中后用双指针法)):
bool isPalindrome1(ListNode* head) {
	ListNode *p=head;
	vector<int> a;
	//将链表中的数据存入容器a 
	while(p!=nullptr){
		a.emplace_back(p->val);
		p=p->next;
	}
	//判断a中的数据是否构成回文
	for(int i=0;i<a.size()/2;i++){
		if(a[i]!=a[a.size()-1-i]){
			return false;
		}
	}
	return true;        
}
代码实现(思路二(快慢指针寻找中间节点+反转链表)):
//1->2->3->null     中间结点2 
//1->2->3->4->null  中间结点3 
//快慢指针查找中间结点
ListNode* findMiddleNode(ListNode *head){
	ListNode *slow=head,*fast=head;
	while(fast!=nullptr&&fast->next!=nullptr){
		fast=fast->next->next;
		slow=slow->next; 
	}
	return slow;
} 

//将后半部分的结点翻转 
ListNode* reverseList(ListNode* head){
	ListNode *tmp=head,*pre=nullptr,*r=head; 
	while(r!=nullptr){
		r=r->next;
		tmp->next=pre;
		pre=tmp;
		tmp=r;
	}
	return pre;
}

//判断前后两端是否构成回文链表 
bool isPalindrome2(ListNode* head) {
	//查找中间结点
	ListNode *middleNode=findMiddleNode(head);
	//通过查找的中间结点将后半部分链表反转。
	ListNode *head2=reverseList(middleNode);
	//用于还原后半部分链表
	ListNode *p=head2;
	//逐个比较前半部分和后半部分是否构成回文链表。
	while(head2!=nullptr){
		if(head->val!=head2->val){
			//将后半部分链表复原。
			reverseList(p);
			return false;
		}
		head=head->next;
		head2=head2->next;
	}
	//将后半部分链表复原
	reverseList(p);
	return true;
}

以思路二为例完成代码调试

#include<iostream>
#include<vector>
using namespace std;

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){}
};
//尾插法创建单链表
ListNode* createList(vector<int> a){
	ListNode *head=nullptr,*tail=nullptr;
	
	for(const auto val:a){
		ListNode *newNode=new ListNode(val);
		if(head==nullptr){
			head=newNode;
			tail=newNode;
		}else{
			tail->next=newNode;
			tail=newNode;
		}
	}
	
	return head;
} 

//1->2->3->null     中间结点2 
//1->2->3->4->null  中间结点3 

//查找中间结点
ListNode* findMiddleNode(ListNode *head){
	ListNode *slow=head,*fast=head;
	while(fast!=nullptr&&fast->next!=nullptr){
		fast=fast->next->next;
		slow=slow->next; 
	}
	return slow;
} 

//将后半部分的结点转置 
ListNode* reverseList(ListNode* head){
	ListNode *tmp=head,*pre=nullptr,*r=head; 
	while(r!=nullptr){
		r=r->next;
		tmp->next=pre;
		pre=tmp;
		tmp=r;
	}
	return pre;
}

//判断前后两端是否构成回文链表 
bool isPalindrome2(ListNode* head) {
	//查找中间结点
	ListNode *middleNode=findMiddleNode(head);
	//将链表后半部分翻转
	ListNode *head2=reverseList(middleNode);
	ListNode *p=head2;
	while(head2!=nullptr){
		if(head->val!=head2->val){
			reverseList(p);
			return false;
		}
		head=head->next;
		head2=head2->next;
	}
	reverseList(p);
	return true;
}


int main(){
	vector<int> a={1,2,2,2,2,2,1};
	ListNode *head=createList(a);
	ListNode *p=head;
	//用于代码调试 
	while(p!=nullptr){
		cout<<p->val<<"->";
		p=p->next;
	}
	cout<<"null\n";

	if(isPalindrome2(head)){
		cout<<"is Palindrome\n";
	}else{
		cout<<"is Not Palindrome\n";
	}
	
	//用于代码调试
	p=head;
	while(p!=nullptr){
		cout<<p->val<<"->";
		p=p->next;
	}
	cout<<"null\n";
	
	return 0;
} 

LeetCode 热题 100_回文链表(24_234)原题链接
欢迎大家和我沟通交流(✿◠‿◠)

;