forked from algorhythms/Algo-Quicksheet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchapterArray.tex
More file actions
156 lines (127 loc) · 5.88 KB
/
Copy pathchapterArray.tex
File metadata and controls
156 lines (127 loc) · 5.88 KB
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
\chapter{Array}
\section{Circular Array}
This section describes common patterns for solving problems with circular arrays.
Normally, we should solve the linear problem and circular problem differently.
\subsection{Circular max sum}
Linear problem can be solved linear with dp algorithm for maximum subarray sum - Section \ref{dpSequence}.
The circular sum should use dp.
Problem description: Given an integer array, find a continuous rotate subarray where the sum of numbers is the biggest. Return the index of the first number and the index of the last number.
\runinhead{Core clues:}
\begin{enumerate}
\item \textbf{State definitions}:
Construct left max sum $L_i$ for max sum over the $[0..i]$ with subarray starting at 0 (\textit{forward} starting from the left side).
Construct right max sum $R_i$ for max sum over the indexes $[i+1..n -1]$, with subarray ending at -1 (\textit{backward} starting from the right side).
Notice, for the two max sums, the index ends AT or BEFORE $i$.
\item \textbf{Transition functions:}
\begin{align*}
L_i = \max\Big(L_{i-1}, sum(A[:i])\Big) \\
R_i = \max\Big(R_{i+1}, sum(A[i:])\Big)
\end{align*}
\item \textbf{Global result}:
$$maxa = \max(R_i+L_{i-1}, \forall i)$$
\end{enumerate}
\subsection{Non-adjacent cell}
Maximum sum of non-adjacent cells in an array $A$.
To solve circular non-adjacent array problem in linear way, we should consider 2 cases:
\begin{enumerate}
\item Not consider the $A[1]$
\item Not consider the $A[-1]$
\end{enumerate}
and solve them using linear maximum sum of non-adjacent cells separately - Section \ref{dpSequence}.
\subsection{Binary search}
Searching for an element in a circular sorted array. Half of the array is sorted while the other half is not.
\begin{enumerate}
\item If $A[0] < A[mid]$, then all values in the first half of the array are sorted.
\item If $A[mid] < A[-1]$, then all values in the second half of the array are sorted.
\item Then \textit{derive and decide} whether to got the \textbf{sorted half} or the \textbf{unsorted half}.
\end{enumerate}
\section{Voting Algorithm}
\subsection{Majority Number}
\subsubsection{$\frac{1}{2}$ of the Size}
Given an array of integers, the majority number is the number that occurs more than half of the size of the array.
Algorithm: Majority Vote Algorithm. Maintain a counter to count how many times the majority number appear more than any other elements before index $i$ and after re-initialization. Re-initialization happens when the counter drops to 0.
Proof: assuming there is a majority number $x$, if at the index $i$, the current count is $j$ and the current counter does not capture the majority number, there are less than $\frac{i-j}{2}$ $x$, thus there are more than $\frac{n-i+j}{2}$ $x$ after the index $i$. The $j$ $x$ beats against the counter and $\frac{n-i-j}{2}$ $x$ will make it counted by counter.
If the counter captures the majority number, two cases will happen. The one is that the counter continue to capture the majority number till the end; then the counter will captures the correct majority number. The other case is that the majority number counter is beaten by other numbers, which will in turn fall back to the case that the counter does not capture the majority number.
This algorithm needs to re-check the current number being counted is indeed the majority number.
\begin{python}
def majorityElement(self, nums):
"""
Algorithm:
O(n lgn) sort and take the middle one
O(n) Moore's Voting Algorithm
"""
mjr = nums[0]
cnt = 0
for i, v in enumerate(nums):
if mjr == v:
cnt += 1
else:
cnt -= 1
if cnt < 0:
mjr = v
cnt = 1
return mjr
\end{python}
\subsubsection{$\frac{1}{3}$ of the Size}
Given an array of integers, the majority number is the number that occurs more than $\frac{1}{3}$ of the size of the array. This question can be generalized to be solved by $\frac{1}{k}$ case.
\subsubsection{$\frac{1}{k}$ of the Size}
Given an array of integers and a number k, the majority number is the number that occurs more than $\frac{1}{k}$ of the size of the array. In this case, we need to generalize the solution to $\frac{1}{2}$ majority number problem.
\newpag
\begin{python}
def majorityNumber(self, nums, k):
"""
Since majority elements appears more
than ceil(n/k) times, there are at
most k-1 majority number
"""
cnt = defaultdict(int)
for num in nums:
if num in cnt:
cnt[num] += 1
else:
if len(cnt) < k-1:
cnt[num] += 1
else:
for key in cnt.keys():
cnt[key] -= 1
if cnt[key] == 0: del cnt[key]
# filter, double-check
for key in cnt.keys():
if (len(filter(lambda x: x == key, nums))
> len(nums)/k):
return key
raise Exception
\end{python}
\section{Two Pointers}
\subsection{Interleaving}
\runinhead{Interleaving positive and negative numbers.} Given an array with positive and negative integers. Re-range it to interleaving with positive and negative integers.
\begin{lstlisting}
Input:
[-33, -19, 30, 26, 21, -9]
Output:
[-33, 30, -19, 26, -9, 21]
\end{lstlisting}
Core clues:
\begin{enumerate}
\item In 1-pass.
\item What (positive or negative) is expected for the current position.
\item Where is the next positive and negative element.
\end{enumerate}
\begin{python}
def rerange(self, A):
n = len(A)
pos_cnt = len(filter(lambda x: x > 0, A))
pos_expt = True if pos_cnt*2 > n else False
neg = 0 # next negative
pos = 0 # next positive
for i in xrange(n):
while neg < n and A[neg] > 0: neg += 1
while pos < n and A[pos] < 0: pos += 1
if pos_expt:
A[i], A[pos] = A[pos], A[i]
else:
A[i], A[neg] = A[neg], A[i]
if i == neg: neg += 1
if i == pos: pos += 1
pos_expt = not pos_expt
\end{python}