|
| 1 | +> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。 |
| 2 | +> |
| 3 | +> 个人博客:https://www.zhangxiaoshuai.fun |
| 4 | +
|
| 5 | +**本题选择leetcode第234题,easy难度,目前通过率41.5%** |
| 6 | + |
| 7 | +```txt |
| 8 | +题目描述: |
| 9 | +请判断一个链表是否为回文链表。 |
| 10 | +示例 1: |
| 11 | + 输入: 1->2 |
| 12 | + 输出: false |
| 13 | +
|
| 14 | +示例 2: |
| 15 | + 输入: 1->2->2->1 |
| 16 | + 输出: true |
| 17 | +``` |
| 18 | + |
| 19 | +***这道题还有进阶版本,我们先实现这个普通版本再看。*** |
| 20 | + |
| 21 | +### 题目分析: |
| 22 | + |
| 23 | +``` |
| 24 | +首先,我们先遍历一遍链表,将链表中的每个值存入数组当中,然后我们判断数组中的元素是否满足回文数条件即可。 |
| 25 | +这里因为我们不知道链表的长度,我们先使用动态数组将值存起来,然后再存到固定大小的数组中。 |
| 26 | +``` |
| 27 | + |
| 28 | +### 解法一gif动画演示: |
| 29 | + |
| 30 | + |
| 31 | + |
| 32 | +### 代码: |
| 33 | + |
| 34 | +```java |
| 35 | +public boolean isPalindrome(ListNode head) { |
| 36 | + List<Integer> list = new ArrayList<>(); |
| 37 | + while (head != null) { |
| 38 | + list.add(head.val); |
| 39 | + head = head.next; |
| 40 | + } |
| 41 | + int[] arr = new int[list.toArray().length]; |
| 42 | + int temp = 0; |
| 43 | + for (int a : list) { |
| 44 | + arr[temp++] = a; |
| 45 | + } |
| 46 | + temp = 0; |
| 47 | + for (int i = 0;i < arr.length/2;i++) { |
| 48 | + if (arr[i] == arr[arr.length-i-1]) { |
| 49 | + temp++; |
| 50 | + } |
| 51 | + } |
| 52 | + if(temp == arr.length/2) return true; |
| 53 | + return false; |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +**时间复杂度:O(n) 空间复杂度:O(n)** |
| 58 | + |
| 59 | +### 进阶: |
| 60 | + |
| 61 | +**你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?** |
| 62 | + |
| 63 | +**思路分析:**我们先找到链表的中间结点,然后将中间结点后面的链表进行反转,反转之后再和前半部分链表进行比较,如果相同则表示该链表属于回文链表,返回true;否则,否则返回false |
| 64 | + |
| 65 | +### 解法二gif动画演示: |
| 66 | + |
| 67 | + |
| 68 | + |
| 69 | +### 代码: |
| 70 | + |
| 71 | +```java |
| 72 | +public boolean isPalindrome(ListNode head) { |
| 73 | + if(head == null || head.next == null) return true; |
| 74 | + ListNode p = new ListNode(-1); |
| 75 | + ListNode low = p; |
| 76 | + ListNode fast = p; |
| 77 | + p.next = head; |
| 78 | + //使用快慢指针来确定中间结点 |
| 79 | + while(fast != null && fast.next != null){ |
| 80 | + low = low.next; |
| 81 | + fast = fast.next.next; |
| 82 | + } |
| 83 | + ListNode cur = low.next; |
| 84 | + ListNode pre = null; |
| 85 | + low.next = null; |
| 86 | + low = p.next; |
| 87 | + |
| 88 | + //反转后半部分链表 |
| 89 | + while(cur != null){ |
| 90 | + ListNode tmp = cur.next; |
| 91 | + cur.next = pre; |
| 92 | + pre = cur; |
| 93 | + cur = tmp; |
| 94 | + } |
| 95 | + //将前半部分链表和后半部分进行比较 |
| 96 | + while(pre != null){ |
| 97 | + if(low.val != pre.val){ |
| 98 | + return false; |
| 99 | + } |
| 100 | + low = low.next; |
| 101 | + pre = pre.next; |
| 102 | + } |
| 103 | + return true; |
| 104 | +} |
| 105 | +``` |
| 106 | + |
| 107 | +**时间复杂度:O(n) 空间复杂度:O(1)** |
| 108 | + |
| 109 | +**没错,可以看到上面的代码是完全能可以通过的,虽然我们完成了题目,但是我们改变了链表的结构,也就是说它现在不是它了;出题人应该是不希望我们破坏链表的,所以在我们完成判断之后,需要将链表恢复原样,也就是将后半部分链表反转之后接到前半部分链表的末尾。** |
0 commit comments