007-判断一个链表是否为回文结构

package com.my.util;
/**
 * 单向链表节点
 * */
public class SingleNode {
	public int value;
	public SingleNode next;
	public SingleNode(int data){
		this.value = data;
	}
}

package com.my.suanfa;

import java.util.Stack;

import com.my.util.SingleNode;

/**
 * 判断一个链表是否为回文结构
 * */
public class Solution04 {
	/*
	 * 方法一:时间复杂度:O(N),额外空间复杂度:O(N)
	 * 					因为需要一个额外的栈,并将链表中元素全部压入栈
	 * */
	public boolean isPalindrome1(SingleNode head) {
		//定义一个栈结构,用来压入链表中的全部元素
		Stack<SingleNode> stack = new Stack<SingleNode>();
		//定义一个临时节点指向链表的头结点
		SingleNode cur = head;
		while(cur != null) {
			stack.push(cur);
			cur = cur.next;
		}
		while(head != null) {
			if(head.value != stack.pop().value) {
				return false;
			}
			head = head.next;
		}
		return true;
	}
	
	/**
	 * 方法二:时间复杂度:O(N),额外空间复杂度:O(N)
	 * 将链表分为左半区和右半区。
	 * 如果链表节点个数位偶数,前n / 2,为左半区的节点,后n / 2为右半区的节点
	 * 如果链表节点个数为奇数,忽略最中间的节点,还是如上分区
	 * 只将链表的右半区压入栈中与左半区比较是否相等,相当于将链表对折进行比较
	 * */
	public boolean isPalindrome2(SingleNode head) {
		//边界条件判断
		if(head == null || head.next == null) {
			return true;
		}
		//遍历链表找到右区的第一个节点
		SingleNode right = head.next;
		SingleNode cur = head;
		/**
		 * 采用双指针法找到右区的第一个节点
		 * cur向右移动两个节点,right向右移动一个节点,那么当cur为空时,right正好指向右区的第一个节点
		满足移动的条件,cur.next != null && cur.next.next != null则right指向的节点一定不是右区的第一个节点
		*/
		while(cur.next != null && cur.next.next != null) {
			right = right.next;
			cur = cur.next.next;
		}
		//定义栈结构一次压入右区的节点
		Stack<SingleNode> stack = new Stack<SingleNode>();
		//将右区元素依次压入栈中
		while(right != null) {
			stack.push(right);
			right = right.next;
		}
		//将栈中元素与左区元素依次比较是否相等
		while(!stack.isEmpty()) {
			if(head.value != stack.pop().value) {
				return false;
			}
			head = head.next;
		}
		return true;
	}
	
	/**
	 * 方法三:时间复杂度O(N),额外空间复杂度O(1)
	 * 不需要栈和其他数据结构,只需要有限几个变量
	 * */
	public boolean isPalindrome3(SingleNode head) {
		//边界条件判断
		if(head == null || head.next == null) {
			return true;
		}
		//定义两个辅助变量
		SingleNode n1 = head;
		SingleNode n2 = head;
		//循环链表找到中部节点
		while(n2.next != null && n2.next.next != null) {
			n1 = n1.next;  	//n1-->中部
			n2 = n2.next.next;
		}
		n2 = n1.next;		//n2-->右区第一个节点
		n1.next = null;		//将n1中间节点的后继节点设为空
		SingleNode n3 = null;
		//反转右区的链表
		while(n2 != null) {
			n3 = n2.next; 		//n3保存右区的下一个节点
			n2.next = n1;		//使右区的第一个节点指向中间节点
			n1 = n2;		//此时中间节点已经不是尾节点,将中间节点向后移动一位
			n2 = n3;		//n2向后移动一位指向右区的下一个节点
		}
		n3 = n1;		//n1-->right start,经上轮遍历可知n1为整个链表的尾节点,此时让n3指向尾节点
		n2 = head;		//n2-->left start
		boolean res = true;		//状态标志位
		//判断链表是否为回文结构
		while(n1 != null && n2 != null) {
			if(n1.value != n2.value) {
				res = false;
				break;
			}
			n1 = n1.next;			//从右向中移动
			n2 = n2.next;		//从左向中移动
		}
		//将链表恢复为原结构
		//此时n3的值没有变化,依然记录的是最后一个节点。从尾开始恢复链表结构
		n1 = n3.next;		//n1记录下一个需要恢复的节点
		n3.next = null;		// 将n3设为尾节点
		while(n1 != null) {
			n2 = n1.next;		//n2记录n1的下一个节点
			n1.next = n3;		//恢复最后一个节点
			n3 = n1;		//n3向后移动一位
			n1 = n2;		//n1向后移动一位
		}
		return res;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值