- Notifications
You must be signed in to change notification settings - Fork 46.7k
/
Copy pathis_palindrome.py
185 lines (146 loc) · 4.52 KB
/
is_palindrome.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
from __future__ importannotations
fromdataclassesimportdataclass
@dataclass
classListNode:
val: int=0
next_node: ListNode|None=None
defis_palindrome(head: ListNode|None) ->bool:
"""
Check if a linked list is a palindrome.
Args:
head: The head of the linked list.
Returns:
bool: True if the linked list is a palindrome, False otherwise.
Examples:
>>> is_palindrome(None)
True
>>> is_palindrome(ListNode(1))
True
>>> is_palindrome(ListNode(1, ListNode(2)))
False
>>> is_palindrome(ListNode(1, ListNode(2, ListNode(1))))
True
>>> is_palindrome(ListNode(1, ListNode(2, ListNode(2, ListNode(1)))))
True
"""
ifnothead:
returnTrue
# split the list to two parts
fast: ListNode|None=head.next_node
slow: ListNode|None=head
whilefastandfast.next_node:
fast=fast.next_node.next_node
slow=slow.next_nodeifslowelseNone
ifslow:
# slow will always be defined,
# adding this check to resolve mypy static check
second=slow.next_node
slow.next_node=None# Don't forget here! But forget still works!
# reverse the second part
node: ListNode|None=None
whilesecond:
nxt=second.next_node
second.next_node=node
node=second
second=nxt
# compare two parts
# second part has the same or one less node
whilenodeandhead:
ifnode.val!=head.val:
returnFalse
node=node.next_node
head=head.next_node
returnTrue
defis_palindrome_stack(head: ListNode|None) ->bool:
"""
Check if a linked list is a palindrome using a stack.
Args:
head (ListNode): The head of the linked list.
Returns:
bool: True if the linked list is a palindrome, False otherwise.
Examples:
>>> is_palindrome_stack(None)
True
>>> is_palindrome_stack(ListNode(1))
True
>>> is_palindrome_stack(ListNode(1, ListNode(2)))
False
>>> is_palindrome_stack(ListNode(1, ListNode(2, ListNode(1))))
True
>>> is_palindrome_stack(ListNode(1, ListNode(2, ListNode(2, ListNode(1)))))
True
"""
ifnotheadornothead.next_node:
returnTrue
# 1. Get the midpoint (slow)
slow: ListNode|None=head
fast: ListNode|None=head
whilefastandfast.next_node:
fast=fast.next_node.next_node
slow=slow.next_nodeifslowelseNone
# slow will always be defined,
# adding this check to resolve mypy static check
ifslow:
stack= [slow.val]
# 2. Push the second half into the stack
whileslow.next_node:
slow=slow.next_node
stack.append(slow.val)
# 3. Comparison
cur: ListNode|None=head
whilestackandcur:
ifstack.pop() !=cur.val:
returnFalse
cur=cur.next_node
returnTrue
defis_palindrome_dict(head: ListNode|None) ->bool:
"""
Check if a linked list is a palindrome using a dictionary.
Args:
head (ListNode): The head of the linked list.
Returns:
bool: True if the linked list is a palindrome, False otherwise.
Examples:
>>> is_palindrome_dict(None)
True
>>> is_palindrome_dict(ListNode(1))
True
>>> is_palindrome_dict(ListNode(1, ListNode(2)))
False
>>> is_palindrome_dict(ListNode(1, ListNode(2, ListNode(1))))
True
>>> is_palindrome_dict(ListNode(1, ListNode(2, ListNode(2, ListNode(1)))))
True
>>> is_palindrome_dict(
... ListNode(
... 1, ListNode(2, ListNode(1, ListNode(3, ListNode(2, ListNode(1)))))
... )
... )
False
"""
ifnotheadornothead.next_node:
returnTrue
d: dict[int, list[int]] = {}
pos=0
whilehead:
ifhead.valind:
d[head.val].append(pos)
else:
d[head.val] = [pos]
head=head.next_node
pos+=1
checksum=pos-1
middle=0
forvind.values():
iflen(v) %2!=0:
middle+=1
else:
forstep, iinenumerate(range(len(v))):
ifv[i] +v[len(v) -1-step] !=checksum:
returnFalse
ifmiddle>1:
returnFalse
returnTrue
if__name__=="__main__":
importdoctest
doctest.testmod()