234.回文链表
题目
- 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false
python
法一、复制+反转链表
- 把原链表翻转一下,与没翻转的链表对比,相同则是回文,返回True,不同则返回False。在进行链表翻转时需要把原链表节点一个一个取下来,用头插法放到新的链表中,导致原链表被拆毁,没法比较了,所以一开始先把原链表复制一份。
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
if not head or not head.next:#空链表和单个节点链表
return True
# 复制链表
new_head = ListNode(0)#定义复制链表的头节点
new_current = new_head
current = head
while current:#当原链表没到链尾时进行复制
new_node = ListNode(current.val)#创建一个新的节点,把原链表当前指针所指的值赋与
new_current.next = new_node#把这个节点加载在新链表
new_current = new_current.next#新链表的当前指针后移
current = current.next#原链表的指针后移
# 反转链表
new_head2 = ListNode(0)#定义反转链表的头节点
pre = head#pre指针指向头
while pre:#当pre没到链表结尾时循环
cur = pre.next#把pre的下一个指针赋给指针cur
pre.next = new_head2.next#把新的头节点的next赋给pre的next
new_head2.next = pre#新的头节点的next指向pre
pre = cur#更新pre
# 比较链表是否回文
i, j = new_head.next, new_head2.next
while i and j:
if i.val != j.val:
return False
i = i.next
j = j.next
return True
- 时间复杂度为 O(n),空间复杂度为 O(n)
法二、堆栈
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
stack = []#创建一个空栈 stack 用于存储链表节点
# step1: push
curr = head
while(curr):#遍历链表
stack.append(curr)#将节点依次压入栈中
curr = curr.next
# step2: pop and compare
node1 = head#链表的当前节点 node1
while(stack):
node2 = stack.pop()#弹出的栈顶元素
if node1.val != node2.val:
return False
node1 = node1.next
return True
- 时间复杂度为 O(n),空间复杂度为 O(n)
法三、快慢指针和链表反转
1.使用快慢指针找到链表的中间节点。快指针每次移动两步,慢指针每次移动一步,当快指针到达链表末尾时,慢指针指向的节点即为链表的中间节点。
2.反转链表的后半部分。从中间节点开始,将后半部分链表进行反转操作。
3.比较链表的前半部分和反转后的后半部分。分别使用两个指针同时遍历两部分链表,比较节点的值是否相等。如果所有节点的值都相等,则链表是回文的;否则,链表不是回文的。
4.恢复链表并返回结果。将反转后的后半部分链表再次进行反转操作,使链表恢复原来的顺序。
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
if not head or not head.next:#空链表和单个节点链表
return True
# 找到链表的中间节点
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 反转后半部分链表
prev = None#prev:前驱节点,指向Null
while slow:
next_node = slow.next # 先把原来slow.next位置存起来
slow.next = prev #改变链表方向
prev = slow #更新prev
slow = next_node #更新slow
# 比较链表的前半部分和反转后的后半部分
p1, p2 = head, prev
while p1 and p2:
if p1.val != p2.val:
return False
p1 = p1.next
p2 = p2.next
# 恢复链表
prev = None
while prev != None:
next_node = p2.next
p2.next = prev
prev = p2
p2 = next_node
return True
- 时间复杂度为 O(n),空间复杂度为 O(1)
javascript
法一、复制+反转链表
- 复制一份链表用头插法翻转链表。两个链表逐个比较
var isPalindrome = function(head) {
let over = head //复制链表
let new_head = null // 初始化翻转后的链表头
while(over!==null){ //头插法翻转链表
let newNode = new ListNode(over.val)
newNode.next=new_head
new_head=newNode
over=over.next
}
//两个链表逐个比较
let p1=head
let p2=new_head
while(p1!==null){
if(p1.val!==p2.val){
return false
}else{
p1=p1.next
p2=p2.next
}
}
return true
};
法二、快慢指针和链表反转
var isPalindrome = function(head) {
//快慢指针找到中点
let fast=head, slow=head
while(fast!==null && fast.next!==null){
slow=slow.next
fast=fast.next.next
}
//翻转后半部分
let pre=null
while(slow!==null){
let next = slow.next
slow.next=pre
pre=slow
slow=next
}
//比较前半部分和后半部分
let p1=head
let p2=pre
while(p2!==null){
if(p1.val!==p2.val){
return false
}else{
p1=p1.next
p2=p2.next
}
}
return true
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理