-
Notifications
You must be signed in to change notification settings - Fork 121
/
chapterLinkedList.tex
142 lines (120 loc) · 3.32 KB
/
chapterLinkedList.tex
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
\chapter{Linked List}
\section{Operations}
\subsection{Fundamentals}
Get the $pre$ reference:
\begin{python}
dummy = Node(0)
dummy.next = head
pre = dummy
cur = pre.next
\end{python}
In majority case, we need a reference to pre.
\subsection{Basic Operations}
\begin{enumerate}
\item Get the length
\item Get the $i$-th object
\item Delete a node
\item Reverse
\begin{figure}[]
\centering
\subfloat{\includegraphics[width=\linewidth]{ll_reverse}}
\caption{Reverse the linked list}
\label{fig:LABEL}
\end{figure}
\begin{python}
def reverseList(self, head):
dummy = ListNode(0)
dummy.next = head
pre = dummy
cur = head # ... = dummy.next, not preferred
while pre and cur:
assert pre.next == cur
nxt = cur.next
# op
cur.next = pre
pre = cur
cur = nxt
# original head pointing to dummy
head.next = None # dummy.next.next = ..., not preferred
return pre # new head
\end{python}
Notice: the evaluation order for the swapping the nodes and links.
\end{enumerate}
\subsection{Combined Operations}
In $O(n)$ without extra space:
\begin{enumerate}
\item Determine whether two lists intersects
\item Determine whether the list is palindrome
\item Determine whether the list is acyclic
\end{enumerate}
\section{Combinations}
\subsection{LRU}
Core clues:
\begin{enumerate}
\item Ensure $O(1)$ find $O(1)$ deletion.
\item Doubly linked list + map.
\item Keep both \pyinline{head} and \pyinline{tail} pointer.
\item Operations on doubly linked list are case by case.
\end{enumerate}
\begin{python}
class Node:
def __init__(self, key, val):
self.key = key
self.val = val
self.pre, self.next = None, None
class LRUCache:
def __init__(self, capacity):
self.cap = capacity
self.map = {} # key to node
self.head = None
self.tail = None
def get(self, key):
if key in self.map:
cur = self.map[key]
self._elevate(cur)
return cur.val
return -1
def set(self, key, value):
if key in self.map:
cur = self.map[key]
cur.val = value
self._elevate(cur)
else:
cur = Node(key, value)
self.map[key] = cur
self._appendleft(cur)
if len(self.map) > self.cap:
last = self._pop()
del self.map[last.key]
# doubly linked-list operations only
def _appendleft(self, cur):
"""Normal or initially empty"""
if not self.head and not self.tail:
self.head = cur
self.tail = cur
return
head = self.head
cur.next, cur.pre, head.pre = head, None, cur # safe
self.head = cur
def _pop(self):
"""Normal or resulting empty"""
last = self.tail
if self.head == self.tail:
self.head, self.tail = None, None
return last
pre = last.pre
pre.next = None
self.tail = pre
return last
def _elevate(self, cur):
"""Head, Tail, Middle"""
pre, nxt = cur.pre, cur.next
if not pre:
return
elif not nxt:
assert self.tail == cur
self._pop()
else:
pre.next, nxt.pre = nxt, pre # safe
self._appendleft(cur)
\end{python}