八.判断列表是否为回文结构(正序倒序都一样)

【题目】

给定一个链表的头节点head,请判断该链表是否为回文结构。
例如: 1->2->1,返回true;1->2->2->1,返回true;15->6->15,返回true; 1->2->3,返回false。

【思路】

【第一种解法】(额外的空间复杂度是O(n))

1.准备一个栈,遍历链表中的数据存到栈中;
2.再遍历一次链表数据,同时把栈中数据依次弹出(相当于把链表数据反序),逐个比较。

【代码实现】

//1.构造链表结构(链表是许多结点构成,结点是数值和指针(指向的是下一个结点)构成)
public static class Node{
		int value;
		Node next;
		public Node(int data) {
			this.value=data;
		}
	}
//2.核心函数
public static boolean isHuiWen(Node head){
	
	//2.1链表中的数据压入栈
	Stack<Node> stack=new Stack<>();
	Node cur=head;
	while(cur!=null){
		stack.push(cur);
		cur=cur.next;
	}
	//2.2 链表中的数据和栈中数据比较
	while(head!=null){
		if(head.value!=stack.pop().value){
			return false;
		}
		head=head.next;
	}
	return true;
}
【第二种解法】(额外的空间复杂度是O(n),但是节省了一半的空间)

1.设定一个快指针cur,每次走两步;
2.设定一个慢指针head,每次走一步;
3.当快指针不能再走的时候,就停止,此时慢指针所在的位置就是中间位置(奇数个结点恰好中间位置,偶数个结点则走到靠后边的中间位置);
4.把慢指针及之后的数据存入到栈中
5.慢指针前面的和栈依次弹出的数据逐个进行比较;

在这里插入图片描述

在这里插入图片描述

【代码实现】

public static boolean isPalindrome2(Node head) {
		//1.没有头结点或者只有头结点返回true
		if (head == null || head.next == null) {
			return true;
		}

		//2.设定慢结点right(为了保证偶数个的时候在后边的中间位置,他从第一个结点开始移动,每次一步);设定快结点cur(从头结点开始走,每次两步)
		Node right = head.next;
		Node cur = head;
		while (cur.next != null && cur.next.next != null) {
			right = right.next;
			cur = cur.next.next;
		}

		//3.把中间位置及其以后的数据放到栈中
		Stack<Node> stack = new Stack<Node>();
		while (right != null) {
			stack.push(right);
			right = right.next;
		}

		//4.不断弹出栈中元素和前面的比较
		while (!stack.isEmpty()) {
			if (head.value != stack.pop().value) {
				return false;
			}
			head = head.next;
		}
		return true;
	}
【第三种解法】

1.找到中间位置;
2.中间位置及其以后结点改变指针指向,让后一个结点指向前一个结点;
3.左半部分和右半部分比较;
4.右半部分调整回原来的指向;

public static boolean isHuiWen3(Node head) {
			if (head==null||head.next==null) {
				return true;
			}
			Node n1=head;
			Node n2=head;
			while(n2.next!=null&&n2.next.next!=null) {
				n1=n1.next;
				n2=n2.next.next;
			}
			
			
		
			//1.改变右part指针方向
			n2=n1.next;//n1移动到中间或者中间靠左位置	//n2是链表右半部分第一个结点
			n1.next=null;//n1是链表左半部分最后一个结点,让他指向空(左半部分和右半部分断开关联)
			Node n3=null;//辅助结点
			//(翻转n2及其以后的节点)1.找到下一个结点 2.找到下一个位置n1  3.把后边的节点移动到他前边的位置
			while(n2!=null) {
				n3=n2.next;//找到下一个结点
				n2.next=n1;//找到下一个结点的位置(改变指针方向,他就相当于是改变之后的前边位置)
				n1=n2;//(把当前节点移动到它的前一位)
				n2=n3;//(把当前节点的后一个结点移动到当前节点的位置)
			}
			



			//2.比较方法
			n3=n1;//n3保存右part最后一个结点
			n2=head;//n2是左part第一个结点
			boolean res=true;
			while(n1!=null&&n2!=null) {
				if(n1.value!=n2.value) {
					res=false;
					break;
				}
				n1=n1.next;
				n2=n2.next;
			}
			
			//3.调整回右part原来的指针指向
			n1=n3.next;//n3保存右part第一个元素,n1是下一个结点
			n3.next=null;//
			while(n1!=null) {
				n2=n1.next;//找到n1的下一个结点
				n1.next=n3;//找到n1的下一个位置(就是之后前边位置)
				n3=n1;//后边的都往前移一个位置
				n1=n2;
			}
			return res;
		}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值