如何判断回文链表 :: labuladong的算法小抄 #1071
Replies: 45 comments 10 replies
-
js 递归后序遍历版 function ListNode(val, next) {
this.val = val === undefined ? 0 : val;
this.next = next === undefined ? null : next;
}
function buildLinkList(values) {
return values.reverse().reduce((acc, val) => new ListNode(val, acc), null);
}
// ---- Generate our linked list ----
const linkedList = buildLinkList(["a"]);
var isPalindrome = function (head) {
// 左侧指针
let left = head;
return traverse(head);
function traverse(right) {
if (right === null) return true;
let res = traverse(right.next);
// 后序遍历代码
res = res && right.val === left.val;
left = left.next;
return res;
}
};
console.log(isPalindrome(linkedList)); |
Beta Was this translation helpful? Give feedback.
-
js 双指针版 function ListNode(val, next) {
this.val = val === undefined ? 0 : val;
this.next = next === undefined ? null : next;
}
function buildLinkList(values) {
return values.reverse().reduce((acc, val) => new ListNode(val, acc), null);
}
// ---- Generate our linked list ----
const linkedList = buildLinkList(["a", "b", "b", "a"]);
var isPalindrome = function (head) {
if (head === null || head.next === null) return head;
let slow = head,
fast = head;
// 寻找链表中点
while (fast !== null && fast.next !== null) {
slow = slow.next;
fast = fast.next.next;
}
// 如果fast指针没有指向null,说明链表长度为奇数,slow还要再前进一步:
if (fast !== null) {
slow = slow.next;
}
// slow 指针现在指向链表中点
// 从slow开始反转后面的链表
let left = head,
right = reverse(slow);
let p = null,
q = right;
// 比较回文串
while (right !== null) {
if (left.val !== right.val) return false;
p = left;
left = left.next;
right = right.next;
}
// 恢复原先链表顺序
p.next = reverse(q);
return true;
function reverse(head) {
let prev = null,
cur = head;
while (cur != null) {
const next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
}
};
console.log(isPalindrome(linkedList)); |
Beta Was this translation helpful? Give feedback.
-
python 双指针版 # Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
slow,fast=head,head
while fast!=None and fast.next!=None:
slow=slow.next
fast=fast.next.next
pre,cur=None,slow
while cur!=None:
nxt= cur.next
cur.next=pre
pre=cur
cur=nxt
while pre!=None:
if pre.val!=head.val:
return False
pre=pre.next
head=head.next
return True |
Beta Was this translation helpful? Give feedback.
-
python 递归版 class Solution:
def __init__(self):
self.left=None
def traverse(self,right):
if right==None:
return True
res=self.traverse(right.next)
res=res and (right.val==self.left.val)
self.left=self.left.next
return res
def isPalindrome(self, head: ListNode) -> bool:
self.left=head
return self.traverse(head) |
Beta Was this translation helpful? Give feedback.
-
是不是也可以通过将中点左侧或者右侧的链表翻转,然后双指针分别从头遍历2个链表判断是不是相同链表? |
Beta Was this translation helpful? Give feedback.
-
Go func isPalindrome(head *ListNode) bool {
slow, fast := head, head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
if fast != nil { // 奇数个节点
slow = slow.Next
}
left := head
right := reverseListNodes(slow)
for right != nil {
if left.Val != right.Val {
return false
}
left = left.Next
right = right.Next
}
return true
}
func reverseListNodes(head *ListNode) *ListNode {
var pre, next *ListNode
cur := head
for cur != nil {
next = cur.Next
cur.Next = pre
pre = cur
cur = next
}
return pre
} |
Beta Was this translation helpful? Give feedback.
-
这里的reverse使用前边的递归反转实现 public boolean isPalindrome(ListNode head) {
ListNode slow, fast;
slow = fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
//如果fast指针没有指向null,说明链表长度为奇数,slow还要再前进一步
if (fast != null) {
slow = slow.next;
}
ListNode left = head;
ListNode right = reverse(slow);
while (right != null) {
if (left.val != right.val) {
return false;
}
left = left.next;
right = right.next;
}
return true;
}
public static ListNode reverse(ListNode head){
if(head == null || head.next == null){
return head;
}
ListNode last = reverse(head.next);
head.next.next = head;
head.next = null;
return last;
} |
Beta Was this translation helpful? Give feedback.
-
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode pre, cur, nxt;
pre = null;
cur = nxt = head;
while (cur != null){
nxt = cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}
while (pre != null && head != null){
if (pre.val != head.val) return false;
pre = pre.next;
head = head.next;
}
return true;
}
} 我的思路是先把链表反过来,然后再遍历pre和head对比值如果存在不同的话就返回false |
Beta Was this translation helpful? Give feedback.
-
原链表已经被破坏,你又没有恢复原链表
|
Beta Was this translation helpful? Give feedback.
-
daka |
Beta Was this translation helpful? Give feedback.
-
文章末尾提到的恢复原链表顺序,我觉得不需要知道p的位置。因为之前翻转链表后半部分时,并没有修改到图中的p.next,而是修改到了slow.next(变成了NULL)。所以恢复时只需要做 reverse(q)即可复原, p.next = reverse(q)没必要做。q的位置可以在回文比对修改right前备份q=right |
Beta Was this translation helpful? Give feedback.
-
打卡 |
Beta Was this translation helpful? Give feedback.
-
if (fast != null)
slow = slow.next; 这一步判断奇偶其实不用也可以吧, 1 -> 2 -> 3 -> 2 -> 1的情况,第一个2的next始终指向3,就算slow从3开始reverse, 最后比较的也是head: 1 -> 2 -> 3 -> null 和 reverse(slow): 1 -> 2 -> 3 -> null |
Beta Was this translation helpful? Give feedback.
-
起始可以把整个链表的值放入一个数组,然后判断是否回文数组也可以 function isPalindrome(head: ListNode | null): boolean {
if (head === null || head.next === null) {
return true;
}
const arr = [];
let cur = head;
while (cur !== null) {
arr.push(cur.val);
cur = cur.next;
}
while (arr.length) {
if (arr.length === 1) {
return true;
}
const left = arr.shift();
const right = arr.pop();
if (left !== right) {
return false;
}
}
return true;
}; |
Beta Was this translation helpful? Give feedback.
-
C++ 后序遍历版 ListNode* left;
bool postOrderTraversal(ListNode* head)
{
if(head == nullptr)
return true;
bool res = postOrderTraversal(head->next);
res = res && (left->val == head->val);
left = left->next;
return res;
}
bool isPalindrome(ListNode* head)
{
left = head;
return postOrderTraversal(head);
} |
Beta Was this translation helpful? Give feedback.
-
leetcode 上我用数组先存储一下的方法为什么 空间和时间都优于递归都方法啊? |
Beta Was this translation helpful? Give feedback.
-
打卡d4 |
Beta Was this translation helpful? Give feedback.
-
c++ 翻转链表版本 bool isPalindrome(ListNode* head) {
ListNode *slow = head, *fast = head;
while(fast->next!=nullptr && fast->next->next!=nullptr){
slow = slow->next;
fast = fast->next->next;
}
ListNode *right = slow->next;
ListNode *left = head;
right = reverse(right);
while(right != nullptr){
if(right->val != left->val) {
slow->next = reverse(right);
return false;
}
left = left->next;
right = right->next;
}
slow->next = reverse(right);
return true;
}
ListNode* reverse(ListNode* left){
ListNode *pre = nullptr, *cur = left;
while(cur != nullptr){
ListNode *next_ = cur->next;
cur->next = pre;
pre = cur;
cur = next_;
}
return pre;
} |
Beta Was this translation helpful? Give feedback.
-
感觉可以不用反转链表, |
Beta Was this translation helpful? Give feedback.
-
这种解法虽然高效,但破坏了输入链表的原始结构,能不能避免这个瑕疵呢 |
Beta Was this translation helpful? Give feedback.
-
翻转链表那里,让slow多走一步(slow = slow->next)完全是多此一举了。当链表个数为奇数时,使用快慢指针找到的就刚好是链表的中间结点,例如:
while (right != nullptr) {
if (left->val != right->val)
return false;
left = left->next;
right = right->next;
} 在这部分代码中最后就相当于判断了3==3,所以slow=slow->next完全没必要。 |
Beta Was this translation helpful? Give feedback.
-
打卡//破坏原始链表结构的Java代码
private ListNode reverse(ListNode head){
ListNode pre,cur,next;
pre=null;
cur=next=head;
while(next!=null){
next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
public boolean isPalindrome(ListNode head) {
//定义快慢指针来找到链表的中点
ListNode slow, fast;
slow = fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
if (fast != null) {
//如果上面的循环中是因为fast.next==null退出的,说明这个链表个数是一个奇数
//这里的反转的起点还要后移一位
slow = slow.next;
}
//反转后面的链表
ListNode newHead = reverse(slow);
ListNode left = head;
ListNode right = newHead;
while (right != null) {
if(left.val!=right.val){
return false;
}
left=left.next;
right=right.next;
}
return true;
}
//没有破坏原始链表结构的Java代码
private ListNode reverse(ListNode head){
ListNode pre,cur,next;
pre=null;
cur=next=head;
while(next!=null){
next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
public boolean isPalindrome(ListNode head) {
//定义快慢指针来找到链表的中点
ListNode slow, fast;
slow = fast = head;
ListNode p=new ListNode();
while (fast != null && fast.next != null) {
p.next=slow;
p=p.next;
slow = slow.next;
fast = fast.next.next;
}
if (fast != null) {
//如果上面的循环中是因为fast.next==null退出的,说明这个链表个数是一个奇数
//这里的反转的起点还要后移一位
p=slow;
slow = slow.next;
}
//反转后面的链表
ListNode newHead = reverse(slow);
ListNode left = head;
ListNode right = newHead;
while (right != null) {
if(left.val!=right.val){
return false;
}
left=left.next;
right=right.next;
}
p.next=reverse(newHead);
return true;
} |
Beta Was this translation helpful? Give feedback.
-
快慢指针找中间节点那里,可以创建一个新的头节点NullNode.next指向head,fast,slow = NullNode,NullNode;这样找到的中间节点mid的下一个节点mid.next可以直接拿来reverse,省去了第二步判断链表长度奇偶的代码。只额外使用了一个ListNode的空间,空间复杂度还是O(1)。 |
Beta Was this translation helpful? Give feedback.
-
python 递归的写法,如果不用global的变量left,也可以采用nonlocal的写法,这样就不改变leetcode题目的结构 class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
left = head
def traverse(head):
nonlocal left
if head is None:
return True
res = traverse(head.next)
res = res and (head.val == left.val)
left = left.next
return res
return traverse(head) |
Beta Was this translation helpful? Give feedback.
-
打卡 |
Beta Was this translation helpful? Give feedback.
-
python 双指针版 # Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseLink(self,head):
pre,cur=None,head
while cur:
nxt=cur.next
cur.next=pre
pre=cur
cur=nxt
return pre
def isPalindrome(self, head: Optional[ListNode]) -> bool:
slow,fast=head,head
while fast and fast.next:
slow=slow.next
fast=fast.next.next
if fast:
slow=slow.next
left,right=head,self.reverseLink(slow)
while right:
if left.val!=right.val:
return False
left=left.next
right=right.next
return True |
Beta Was this translation helpful? Give feedback.
-
好奇,能不能使用这个思路去判断一个二叉树是否对称 |
Beta Was this translation helpful? Give feedback.
-
碉堡了!真的,链表玩出了新高度! |
Beta Was this translation helpful? Give feedback.
-
学习了。 |
Beta Was this translation helpful? Give feedback.
-
问东哥 图是用啥软件画的? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
文章链接点这里:如何判断回文链表
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions