问题描述
请判断一个链表是否为回文链表。链表为单向无环链表
示例 1:
输入: 1->2 输出: false
示例 2:
输入: 1->2->2->1 输出: true
解法一:
这题是让判断链表是否是回文链表,所谓的回文链表就是以链表中间为中心点两边对称。我们常见的有判断一个字符串是否是回文字符串,这个比较简单,可以使用两个指针,一个最左边一个最右边,两个指针同时往中间靠,判断所指的字符是否相等。
但这题判断的是链表,因为这里是单向链表,只能从前往后访问,不能从后往前访问,所以使用判断字符串的那种方式是行不通的。但我们可以通过找到链表的中间节点然后把链表后半部分反转,最后再用后半部分反转的链表和前半部分一个个比较即可。这里以示例2为例画个图看一下。
最后再来看下代码:
public boolean isPalindrome(ListNode head) { ListNode slow = head, fast = head; //快慢指针 while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } //如果fast不为空,说明链表的长度是奇数个 if (fast != null) { slow=slow.next; } //反转后半部分链表 slow = reverse(slow); fast=head; while (slow!=null){ //不是回文 if (fast.val!=slow.val){ return false; } slow=slow.next; fast=fast.next; } return true; } //反转链表 public ListNode reverse(ListNode head) { ListNode pre = null; while (head != null) { ListNode next = head.next; head.next = pre; pre = next; head = next; } return pre; }
解法二:
我们知道栈是先进后出的一种数据结构,这里还可以使用栈先把链表的节点全部存放到栈中,然后再一个个出栈,这样就相当于链表从后往前访问了,通过这种方式也能解决,看下代码:
public boolean isPalindrome1(ListNode head) { if (head == null) { return true; } ListNode temp = head; Stack<Integer> stack = new Stack(); int len = 0; while (temp != null) { stack.push(temp.val); temp = temp.next; len++; } //长度除以2 len >>= 1; while (len-- > 0) { if (head.val != stack.pop()) { return false; } head = head.next; } return true; }
解法三(递归):
ListNode temp; public boolean isPalindrome2(ListNode head) { temp = head; return check(temp); } private boolean check(ListNode head) { if (head == null){ return true; } //逆序打印链表 boolean res = check(head.next) && (temp.val == head.val); temp = temp.next; return res; }
总结:
回文链表的判断,相比回文字符串的判断稍微要麻烦一点,但难度也不是很大,如果对链表比较熟悉的话,这3种解决方式都很容易想到,如果不熟悉的话,可能最容易想到的就是第2种了,也就是栈和链表的结合。