以专题的形式更新刷题贴,欢迎跟我一块儿学习刷题,相信我,你的坚持,绝对会有意想不到的收获。每道题会提供简单的解答,若是你有更优雅的作法,欢迎提供指点,谢谢。ide
注:若是你在看代码的时候发现代码排版乱了麻烦告诉我一声,谢谢。学习
给定一个链表的头节点 head, 请判断该链表是否为回文结构。3d
例如:指针
1->2->1,返回 true.code
1->2->2->1, 返回 true。blog
1->2->3,返回 false。it
若是链表的长度为 N, 时间复杂度达到 O(N)。ast
普通解法:士:★☆☆☆class
进阶解法:尉:★★☆☆进阶
方法1
咱们能够利用栈来作辅助,把链表的节点所有入栈,在一个一个出栈与链表进行对比,例如对于链表 1->2->3->2->2,入栈后如图:
而后再逐一出栈与链表元素对比。
这种解法比较简单,时间复杂度为 O(n), 空间复杂度为 O(n)。
1//方法1 2public static boolean f1(Node head) { 3 if (head == null || head.next == null) { 4 return true; 5 } 6 Node temp = head; 7 Stack<Node> stack = new Stack<>(); 8 while (temp != null) { 9 stack.push(temp); 10 temp = temp.next; 11 } 12 while (!stack.isEmpty()) { 13 Node t = stack.pop(); 14 if (t.value != head.value) { 15 return false; 16 } 17 head = head.next; 18 } 19 return true; 20}
真的须要所有入栈吗?其实咱们也能够让链表的后半部分入栈就能够了,而后把栈中的元素与链表的前半部分对比,例如 1->2->3->2->2 后半部分入栈后如图:
而后逐个出栈,与链表的前半部分(1->2)对比。这样作的话空间复杂度会减小一半。
代码以下:
1//方法2 2public static boolean f(Node head) { 3 if(head == null || head.next == null) 4 return true; 5 Node slow = head;//慢指针 6 Node fast = head;//快指针 7 Stack<Node> stack = new Stack<>(); 8 //slow最终指向中间节点 9 while (fast.next != null && fast.next.next != null) { 10 slow = slow.next; 11 fast = fast.next.next; 12 } 13 System.out.println(slow.value); 14 slow = slow.next; 15 while (slow != null) { 16 stack.push(slow); 17 slow = slow.next; 18 } 19 //进行判断 20 while (!stack.isEmpty()) { 21 Node temp = stack.pop(); 22 if (head.value != temp.value) { 23 return false; 24 } 25 head = head.next; 26 } 27 return true; 28}
方法三:空间复杂度为 O(1)。
上道题咱们有做过链表的反转的,没看过的能够看一下勒:【链表问题】如何优雅着反转单链表],咱们能够把链表的后半部分进行反转,而后再用后半部分与前半部分进行比较就能够了。这种作法额外空间复杂度只须要 O(1), 时间复杂度为 O(n)。
代码以下:
1//方法3 2public static boolean f2(Node head) { 3 if(head == null || head.next == null) 4 return true; 5 Node slow = head;//慢指针 6 Node fast = head;//快指针 7 //slow最终指向中间节点 8 while (fast.next != null && fast.next.next != null) { 9 slow = slow.next; 10 fast = fast.next.next; 11 } 12 Node revHead = reverse(slow.next);//反转后半部分 13 //进行比较 14 while (revHead != null) { 15 System.out.println(revHead.value); 16 if (revHead.value != head.value) { 17 return false; 18 } 19 head = head.next; 20 revHead = revHead.next; 21 } 22 return true; 23} 24//反转链表 25private static Node reverse(Node head) { 26 if (head == null || head.next == null) { 27 return head; 28 } 29 Node newHead = reverse(head.next); 30 head.next.next = head; 31 head.next = null; 32 return newHead; 33}
思考:若是给你的是一个环形链表,而且指定了头节点,那么该如何判断是否为回文链表呢?
无
无
未知。
无。此题为开放题,你能够根据这个设定各类其余要求条件。
【链表问题】环形单链表约瑟夫问题
【链表问题】如何优雅着反转单链表
【链表问题】删除单链表的中间节点
【链表问题】删除单链表中的第K个节点