回文字符串
我们把正读和反读都一致的字符串叫做回文字符串(Palindrome String),形如 testtset
。
链表判断回文字符串思路
- 使用快慢两个指针找到链表中点,慢指针每次前进一步,快指针每次前进两步。这样当快指针指向末尾时,慢指针指向了中位点(奇数)或者中位点后一位(偶数);
- 将慢指针指向剩余的链表作为一个新链表 next_node。此前在慢指针前进的过程中,通过修改其 next 指针指向上一个元素prev,使得链表前半部分反序,形成列表 prev_node。如果字符串为奇数,next_node 还需要再前进一步,这样才能使得分割开的两个链表长度相等,且中位点不需要判断;
- 遍历两个新链表 next_node 和 prev_node 的所有值,一致则为回文字符串,不一致则不是,代码如下:
class ListNode(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
class StringLinkedList:
def __init__(self, value: str):
self.head = ListNode(None, None)
p = self.head
# 装载字符串
for ch in value:
p.next = ListNode(ch)
p = p.next
self.head = self.head.next
@staticmethod
def to_string(head: ListNode):
values = []
p = head
while p:
values.append(str(p.value))
p = p.next
return ''.join(values)
def __repr__(self):
return self.to_string(self.head)
@staticmethod
def insert_to_head(prev_node, node) -> ListNode:
if not prev_node.value:
return node
node.next = prev_node
return node
def is_palindrome(self) -> bool:
p = self.head
# 链表为空,直接返回 false
if not p.next:
return False
slow = p
fast = p
prev_node = ListNode(None)
while fast and fast.next:
prev_node = self.insert_to_head(prev_node, ListNode(slow.value))
# 快指针每次前进两步
fast = fast.next.next
# 慢指针每次前进一步
slow = slow.next
next_node = slow
# 当为偶数是,快指针指向尾部时循环结束,此时慢指针指向中位点后一位
# 如果快指针仍然有值,表示该字符串为奇数,慢指针正好在中位点,两链表不对称,慢指针需要前进一位
if fast:
next_node = next_node.next
while prev_node:
if prev_node.value != next_node.value:
return False
prev_node = prev_node.next
next_node = next_node.next
return True
if __name__ == '__main__':
linked_list = StringLinkedList("21112")
print(linked_list)
print(linked_list.is_palindrome())
linked_list = StringLinkedList("abcdba")
print(linked_list)
print(linked_list.is_palindrome())
linked_list = StringLinkedList("test_tset")
print(linked_list)
print(linked_list.is_palindrome())
linked_list = StringLinkedList("testtset")
print(linked_list)
print(linked_list.is_palindrome())
终端结果输出如下:
21112
True
abcdba
False
test_tset
True
testtset
True
最后,通过链表实现的回文字符串判断的时间复杂度为:$ O(n) $。