[LeetCode] 234. Palindrome Linked List(回文单链表)
-
Difficulty: Easy
-
Related Topics: Linked List, Two Pointers
Description
Given a singly linked list, determine if it is a palindrome.
给定一个单链表,判断其是否为回文结构。
Examples
Example 1
Input: 1->2
Output: false
Example 2
Input: 1->2->2->1
Output: true
Follow up
Could you do it in O(n) time and O(1) space?
你能用 O(N) 时间复杂度和 O(1) 空间复杂度解决吗?
Solution
普通的解法比较简单:两次遍历,第一次遍历时将链表所有值压入栈内;第二次遍历时,从栈内依次弹出元素值与之进行比较。由于栈先进后出的特性,这时弹出元素的顺序恰好与输入顺序相反,如果链表是回文结构,这两个序列应该是相同的,代码如下:
/**
* Example:
* var li = ListNode(5)
* var v = li.`val`
* Definition for singly-linked list.
* class ListNode(var `val`: Int) {
* var next: ListNode? = null
* }
*/
class Solution {
fun isPalindrome(head: ListNode?): Boolean {
if (head == null) {
return true
}
val stack = ArrayDeque<Int>()
var p = head
while (p != null) {
stack.push(p.`val`)
p = p.next
}
p = head
while (p != null) {
if (p.`val` != stack.pop()) {
return false
}
p = p.next
}
return true
}
}
当然,上述方法中,不需要将链表的所有元素入栈,只需把链表的前半段元素入栈即可进行判断。进阶解法(要求 O(1) 空间复杂度)也不是很难,大致分为以下几个步骤:
-
找到链表的中点(双指针法)
-
反转链表的后半段
-
进行比较
-
(可选)如果题目要求不能改变链表结构,那么记得程序结束前把链表还原
代码如下:
/**
* Example:
* var li = ListNode(5)
* var v = li.`val`
* Definition for singly-linked list.
* class ListNode(var `val`: Int) {
* var next: ListNode? = null
* }
*/
class Solution {
fun isPalindrome(head: ListNode?): Boolean {
if (head?.next == null) {
return true
}
val mid = midNode(head)
val head2 = reverse(mid)
var p = head
var q = head2
while (p != null && q != null) {
if (p.`val` != q.`val`) {
return false
}
p = p.next
q = q.next
}
return true
}
private fun midNode(head: ListNode?): ListNode? {
if (head == null) {
return head
}
var slow = head
var fast = head
while (slow != null && fast != null) {
slow = slow.next
fast = fast.next?.next
}
return slow
}
private fun reverse(head: ListNode?): ListNode? {
var pre: ListNode? = null
var mHead = head
while (mHead != null) {
val next = mHead.next
mHead.next = pre
pre = mHead
mHead = next
}
return pre
}
}