算法题010 -- [判断一个单链表是否是回文链表] by java

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cjh_android/article/details/84029011

题目

判断一个单链表是否是回文链表。

如:[1, 2, 3, 2, 1],[1, 2, 3, 3, 2, 1] 就是一个回文链表,正着依次看链表中元素和反着依次看链表中元素都是一样的。

要求:

时间复杂度 O(n)
空间复杂度 O(1)

代码

package algorithm010;

import algorithm006.ListNode;

public class Algorithm010 {

	public static void main(String[] args) {
		System.out.println(isPalindromeLinkedList(getListNode1()));
		System.out.println(isPalindromeLinkedList2(getListNode2()));
	}
	
	/**方法一
	 * 思路:特殊值记录 + 单链反转
	 * 		在空间复杂度是O(1)的限制下
	 * 		可以使用一个变量在遍历链表的过程中,sun += 该节点所对应的值,
	 * 		需要设计的技巧在于这个值必须是特殊唯一的值
	 * 		如算法中,我设定的对应的值就是用 sum = content * pos
	 * 		如果链表是回文链表,那么从链表的最后一个元素反着来,依次减去节点相应的值
	 * 		那么最后 sum 必然回归于 0,否则该链表就不是一个回文链表。
	 * 		那么就在反转链表的遍历中,处理 sum 值的叠加
	 * 优点:思路比较清晰,简单,时间复杂度 O(2n),其实就是 O(n),写成O(2n)只不过是要与方法二有个比较
	 * 缺点:这个方法适用于content是整数的情况,如果是一个字符串,就不太合适了
	 * 
	 * @param listNode
	 * @return
	 */
	public static boolean isPalindromeLinkedList(ListNode listNode) {
		long sum = 0;
		long factor = 1;
		ListNode pre = null;
		ListNode headNode = null;
		while(listNode != null) {
			sum += listNode.content * factor;
			factor ++;
			ListNode tempNext = listNode.next;
			listNode.next = pre;
			pre = listNode;
			if(null == tempNext)
				headNode = listNode;
			listNode = tempNext;
		}
		factor = 1;
		while(headNode != null) {
			sum -= headNode.content * factor;
			factor ++;
			headNode = headNode.next;
		}
		return sum == 0;
	}
	
	/**方法二
	 * 思路:寻找中间节点,然后反转从中间节点后的链表,再与之前的链表比较
	 * 		比较:遍历中间节点的过程中,同时遍历前半部分链表
	 * 			 如果在同一个循环中出现两个链表的content不同,那么就不成立是回文链表
	 * 		注意:因为遍历的是后半部分反转后的链表,所以必须保证后半部分反转生成的链表长度必须不大于前半部分
	 * 		难点1:如果寻找中间节点
	 * 			  在代码中利用了两种方式寻找中间节点,见 getMiddleHeadNodeBy2Length、getMiddleHeadNodeBy2Pointer
	 * 		难点2:如果保证后半部分的节点的长度不大于前半部分 
	 * 			  这里其实用实际链表来形容就是:
	 * 			  在 【0,1,2,3,2,1,0】,必须返回后半部分的节点 2
	 * 			  在 【0,1,2,3,3,2,1,0】,必须返回后半部分的节点 3
	 * 优点:getMiddleHeadNodeBy2Length 方法下 时间复杂度 O(2n) 
	 * 		getMiddleHeadNodeBy2Pointer 方法下 时间复杂度 O(3/2n) 
	 * 		适用于所有链表
	 * 
	 * @param listNode
	 * @return
	 */
	public static boolean isPalindromeLinkedList2(ListNode listNode) {
//		ListNode middleHeadNode = getMiddleHeadNodeBy2Length(listNode);
		ListNode middleHeadNode = getMiddleHeadNodeBy2Pointer(listNode);
		System.out.println(middleHeadNode.toString());
		ListNode reverseLinkedList = reverseLinkedList(middleHeadNode, null);
		System.out.println(reverseLinkedList.toString());
		while(reverseLinkedList != null) {
			if(listNode.content != reverseLinkedList.content) {
				return false;
			}
			listNode = listNode.next;
			reverseLinkedList = reverseLinkedList.next;
		}
		return true;
	}
	
	/**
	 * 递归反转链表
	 * @param listNode
	 * @param pre
	 * @return
	 */
	private static ListNode reverseLinkedList(ListNode listNode, ListNode pre) {
		if(listNode.next == null) {
			listNode.next = pre;
			return listNode;
		}
		ListNode tempNode = listNode.next;
		listNode.next = pre;
		pre = listNode;
		listNode = tempNode;
		return reverseLinkedList(listNode, pre);
	}

	/**
	 * 利用长度寻找中间节点
	 * @param listNode
	 * @return
	 */
	public static ListNode getMiddleHeadNodeBy2Length(ListNode listNode) {
		int step = (int) Math.ceil(getLinkedListLength(listNode)/2f);//保证返回的是中间节点的坐标
		//提前给 temp赋值,其实就是保证在下面的遍历结束后,temp返回的总是比中间节点前进一位
		ListNode temp = listNode;
		while(step > 0) {
			if(null == temp)
				temp = listNode;
			else 
				temp = temp.next;
			step --;
		}
		return temp;
	}
	
	/**
	 * 双指针寻找中间节点
	 * @param listNode
	 * @return
	 */
	public static ListNode getMiddleHeadNodeBy2Pointer(ListNode listNode) {
		ListNode slowPointer = listNode;
		ListNode fastPointer = listNode.next;
		if(null == fastPointer)
			return slowPointer;
		while(slowPointer != null && fastPointer != null) {
			slowPointer = slowPointer.next;
			if(null == fastPointer.next) {
				break;
			}
			fastPointer = fastPointer.next.next;
		}
		return slowPointer;
	}
	
	/**
	 * 获取链表长度
	 * 
	 * @param listNode
	 * @return
	 */
	public static float getLinkedListLength(ListNode listNode) {
		float length = 0;
		while(listNode != null) {
			length ++;
			listNode = listNode.next;
		}
		return length;
	}
	
	public static ListNode getListNode1() {
		ListNode listNode2 = new ListNode(0);
		ListNode listNode4 = new ListNode(1);
		ListNode listNode6 = new ListNode(2);
		ListNode listNode8 = new ListNode(3);
		ListNode listNode10 = new ListNode(3);
		ListNode listNode11 = new ListNode(2);
		ListNode listNode12 = new ListNode(1);
		ListNode listNode13 = new ListNode(0);
		listNode2.next = listNode4;
		listNode4.next = listNode6;
		listNode6.next = listNode8;
		listNode8.next = listNode10;
		listNode10.next = listNode11;
		listNode11.next = listNode12;
		listNode12.next = listNode13;
		return listNode2;
	}
	
	public static ListNode getListNode2() {
		ListNode listNode2 = new ListNode(0);
		ListNode listNode4 = new ListNode(1);
		ListNode listNode6 = new ListNode(2);
		ListNode listNode8 = new ListNode(3);
		ListNode listNode10 = new ListNode(2);
		ListNode listNode11 = new ListNode(1);
		ListNode listNode12 = new ListNode(0);
		listNode2.next = listNode4;
		listNode4.next = listNode6;
		listNode6.next = listNode8;
		listNode8.next = listNode10;
		listNode10.next = listNode11;
		listNode11.next = listNode12;
		return listNode2;
	}
}

猜你喜欢

转载自blog.csdn.net/cjh_android/article/details/84029011
今日推荐