剑指 Offer II 027. 回文链表(234. 回文链表)
题目:
思路:
【1】使用快慢指针找出中间,进行反转后再比较的方式(因为如果复原的话,是需要考虑后面还会不会用,其实不会用的话不复原都是可以的,毕竟好多都是直接在上面空间进行修改来节省空间)
【2】将值复制到数组中后用双指针法(这种就类似于处理回文字符串了)
【3】使用递归的方式
代码展示:
使用递归的方式:
//时间16 ms击败18.10% //内存58.4 MB击败19.79% //时间复杂度:O(n),其中 n 指的是链表的大小。 //空间复杂度:O(n),其中 n 指的是链表的大小。 //因为在一个函数中调用一个函数时,计算机需要在进入被调用函数之前跟踪它在当前函数中的位置(以及任何局部变量的值),通过运行时存放在堆栈中来实现(堆栈帧),所以在使用递归时空间复杂度要考虑堆栈的使用情况。 class Solution { private ListNode frontPointer; private boolean recursivelyCheck(ListNode currentNode) { if (currentNode != null) { if (!recursivelyCheck(currentNode.next)) { return false; } if (currentNode.val != frontPointer.val) { return false; } frontPointer = frontPointer.next; } return true; } public boolean isPalindrome(ListNode head) { frontPointer = head; return recursivelyCheck(head); } }
将值复制到数组中后用双指针法的方式:
//时间8 ms击败41.19% //内存53.4 MB击败83.27% class Solution { public boolean isPalindrome(ListNode head) { List<Integer> vals = new ArrayList<Integer>(); // 将链表的值复制到数组中 ListNode currentNode = head; while (currentNode != null) { vals.add(currentNode.val); currentNode = currentNode.next; } // 使用双指针判断是否回文 int front = 0; int back = vals.size() - 1; while (front < back) { if (!vals.get(front).equals(vals.get(back))) { return false; } front++; back--; } return true; } }
使用快慢指针找出中间,进行反转后再比较的方式:
不对原本链表进行复原:
//时间3 ms击败99.58% //内存58.2 MB击败21.20% //时间复杂度:O(n),其中 n 指的是链表的大小。 //空间复杂度:O(1)。我们只会修改原本链表中节点的指向。 /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ class Solution { public boolean isPalindrome(ListNode head) { ListNode pre = null; ListNode slow = head; ListNode fast = head; while(fast != null && fast.next != null){ ListNode temp = slow.next; if(pre != null) { slow.next = pre; } pre = slow; fast = fast.next.next; slow = temp; } if(fast != null) slow = slow.next; while(slow != null){ if(slow.val != pre.val) return false; slow = slow.next; pre = pre.next; } return true; } }
对原本链表进行复原:
//时间5 ms击败62.82% //内存51.3 MB击败97.25% class Solution { public boolean isPalindrome(ListNode head) { if (head == null) { return true; } // 找到前半部分链表的尾节点并反转后半部分链表 ListNode firstHalfEnd = endOfFirstHalf(head); ListNode secondHalfStart = reverseList(firstHalfEnd.next); // 判断是否回文 ListNode p1 = head; ListNode p2 = secondHalfStart; boolean result = true; while (result && p2 != null) { if (p1.val != p2.val) { result = false; } p1 = p1.next; p2 = p2.next; } // 还原链表并返回结果 firstHalfEnd.next = reverseList(secondHalfStart); return result; } private ListNode reverseList(ListNode head) { ListNode prev = null; ListNode curr = head; while (curr != null) { ListNode nextTemp = curr.next; curr.next = prev; prev = curr; curr = nextTemp; } return prev; } private ListNode endOfFirstHalf(ListNode head) { ListNode fast = head; ListNode slow = head; while (fast.next != null && fast.next.next != null) { fast = fast.next.next; slow = slow.next; } return slow; } }