Improve language
This commit is contained in:
parent
c6a24af52d
commit
9d61b10876
|
@ -305,7 +305,7 @@ This should take at least some tens of seconds,
|
||||||
so the algorithm seems to be too slow for solving the problem.
|
so the algorithm seems to be too slow for solving the problem.
|
||||||
|
|
||||||
On the other hand, given the input size,
|
On the other hand, given the input size,
|
||||||
we can try to guess
|
we can try to \emph{guess}
|
||||||
the required time complexity of the algorithm
|
the required time complexity of the algorithm
|
||||||
that solves the problem.
|
that solves the problem.
|
||||||
The following table contains some useful estimates
|
The following table contains some useful estimates
|
||||||
|
@ -325,7 +325,7 @@ $n$ is large & $O(1)$ or $O(\log n)$ \\
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
For example, if the input size is $n=10^5$,
|
For example, if the input size is $n=10^5$,
|
||||||
it should probably be expected that the time
|
it is probably expected that the time
|
||||||
complexity of the algorithm is $O(n)$ or $O(n \log n)$.
|
complexity of the algorithm is $O(n)$ or $O(n \log n)$.
|
||||||
This information makes it easier to design the algorithm,
|
This information makes it easier to design the algorithm,
|
||||||
because it rules out approaches that would yield
|
because it rules out approaches that would yield
|
||||||
|
@ -335,7 +335,7 @@ an algorithm with a worse time complexity.
|
||||||
|
|
||||||
Still, it is important to remember that a
|
Still, it is important to remember that a
|
||||||
time complexity is only an estimate of efficiency,
|
time complexity is only an estimate of efficiency,
|
||||||
because it hides the \key{constant factors}.
|
because it hides the \emph{constant factors}.
|
||||||
For example, an algorithm that runs in $O(n)$ time
|
For example, an algorithm that runs in $O(n)$ time
|
||||||
may perform $n/2$ or $5n$ operations.
|
may perform $n/2$ or $5n$ operations.
|
||||||
This has an important effect on the actual
|
This has an important effect on the actual
|
||||||
|
@ -357,8 +357,9 @@ time and even in $O(n)$ time.
|
||||||
Given an array of $n$ numbers,
|
Given an array of $n$ numbers,
|
||||||
our task is to calculate the
|
our task is to calculate the
|
||||||
\key{maximum subarray sum}, i.e.,
|
\key{maximum subarray sum}, i.e.,
|
||||||
the largest possible sum of numbers
|
the largest possible sum of
|
||||||
in a contiguous region in the array\footnote{J. Bentley's
|
a sequence of consecutive numbers
|
||||||
|
in the array\footnote{J. Bentley's
|
||||||
book \emph{Programming Pearls} \cite{ben86} made the problem popular.}.
|
book \emph{Programming Pearls} \cite{ben86} made the problem popular.}.
|
||||||
The problem is interesting when there may be
|
The problem is interesting when there may be
|
||||||
negative numbers in the array.
|
negative numbers in the array.
|
||||||
|
@ -398,8 +399,8 @@ the following subarray produces the maximum sum $10$:
|
||||||
|
|
||||||
\subsubsection{Algorithm 1}
|
\subsubsection{Algorithm 1}
|
||||||
|
|
||||||
Let us assume that the numbers are stored in
|
Assume that the numbers are stored in
|
||||||
an array \texttt{x}.
|
an array \texttt{t}.
|
||||||
A straightforward way to solve the problem
|
A straightforward way to solve the problem
|
||||||
is to go through all possible ways of
|
is to go through all possible ways of
|
||||||
selecting a subarray, calculate the sum of
|
selecting a subarray, calculate the sum of
|
||||||
|
@ -408,23 +409,23 @@ the maximum sum.
|
||||||
The following code implements this algorithm:
|
The following code implements this algorithm:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
int p = 0;
|
int best = 0;
|
||||||
for (int a = 0; a < n; a++) {
|
for (int a = 0; a < n; a++) {
|
||||||
for (int b = a; b < n; b++) {
|
for (int b = a; b < n; b++) {
|
||||||
int s = 0;
|
int sum = 0;
|
||||||
for (int c = a; c <= b; c++) {
|
for (int k = a; k <= b; k++) {
|
||||||
s += x[c];
|
sum += t[k];
|
||||||
}
|
}
|
||||||
p = max(p,s);
|
best = max(best,sum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cout << p << "\n";
|
cout << best << "\n";
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
The variables $a$ and $b$ determine the first and last
|
The variables \texttt{a} and \texttt{b} determine the first and last
|
||||||
number in the subarray,
|
number in the subarray,
|
||||||
and the sum of the numbers is calculated to the variable $s$.
|
and the sum of the numbers is calculated to the variable \texttt{sum}.
|
||||||
The variable $p$ contains the maximum sum found during the search.
|
The variable \texttt{best} contains the maximum sum found during the search.
|
||||||
|
|
||||||
The time complexity of the algorithm is $O(n^3)$,
|
The time complexity of the algorithm is $O(n^3)$,
|
||||||
because it consists of three nested loops
|
because it consists of three nested loops
|
||||||
|
@ -432,22 +433,22 @@ that go through the input.
|
||||||
|
|
||||||
\subsubsection{Algorithm 2}
|
\subsubsection{Algorithm 2}
|
||||||
|
|
||||||
It is easy to make the first algorithm more efficient
|
It is easy to make Algorithm 1 more efficient
|
||||||
by removing one loop from it.
|
by removing one loop from it.
|
||||||
This is possible by calculating the sum at the same
|
This is possible by calculating the sum at the same
|
||||||
time when the right end of the subarray moves.
|
time when the right end of the subarray moves.
|
||||||
The result is the following code:
|
The result is the following code:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
int p = 0;
|
int best = 0;
|
||||||
for (int a = 0; a < n; a++) {
|
for (int a = 0; a < n; a++) {
|
||||||
int s = 0;
|
int sum = 0;
|
||||||
for (int b = a; b < n; b++) {
|
for (int b = a; b < n; b++) {
|
||||||
s += x[b];
|
sum += t[b];
|
||||||
p = max(p,s);
|
best = max(best,sum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cout << p << "\n";
|
cout << best << "\n";
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
After this change, the time complexity is $O(n^2)$.
|
After this change, the time complexity is $O(n^2)$.
|
||||||
|
|
||||||
|
@ -456,8 +457,8 @@ After this change, the time complexity is $O(n^2)$.
|
||||||
Surprisingly, it is possible to solve the problem
|
Surprisingly, it is possible to solve the problem
|
||||||
in $O(n)$ time\footnote{In \cite{ben86}, this linear-time algorithm
|
in $O(n)$ time\footnote{In \cite{ben86}, this linear-time algorithm
|
||||||
is attributed to J. B. Kadene, and the algorithm is sometimes
|
is attributed to J. B. Kadene, and the algorithm is sometimes
|
||||||
called \index{Kadene's algorithm} \key{Kadene's algorithm}.}, which means that we can remove
|
called \index{Kadene's algorithm} \key{Kadene's algorithm}.}, which means
|
||||||
one more loop.
|
that just one loop is enough.
|
||||||
The idea is to calculate, for each array position,
|
The idea is to calculate, for each array position,
|
||||||
the maximum sum of a subarray that ends at that position.
|
the maximum sum of a subarray that ends at that position.
|
||||||
After this, the answer for the problem is the
|
After this, the answer for the problem is the
|
||||||
|
@ -472,21 +473,22 @@ There are two possibilities:
|
||||||
at position $k-1$, followed by the element at position $k$.
|
at position $k-1$, followed by the element at position $k$.
|
||||||
\end{enumerate}
|
\end{enumerate}
|
||||||
|
|
||||||
Our goal is to find a subarray with maximum sum,
|
In the latter case, since we want to
|
||||||
so in case 2 the subarray that ends at position $k-1$
|
find a subarray with maximum sum,
|
||||||
|
the subarray that ends at position $k-1$
|
||||||
should also have the maximum sum.
|
should also have the maximum sum.
|
||||||
Thus, we can solve the problem efficiently
|
Thus, we can solve the problem efficiently
|
||||||
when we calculate the maximum subarray sum
|
by calculating the maximum subarray sum
|
||||||
for each ending position from left to right.
|
for each ending position from left to right.
|
||||||
|
|
||||||
The following code implements the algorithm:
|
The following code implements the algorithm:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
int p = 0, s = 0;
|
int best = 0, sum = 0;
|
||||||
for (int k = 0; k < n; k++) {
|
for (int k = 0; k < n; k++) {
|
||||||
s = max(x[k],s+x[k]);
|
sum = max(t[k],sum+t[k]);
|
||||||
p = max(p,s);
|
best = max(best,sum);
|
||||||
}
|
}
|
||||||
cout << p << "\n";
|
cout << best << "\n";
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
The algorithm only contains one loop
|
The algorithm only contains one loop
|
||||||
|
@ -510,7 +512,7 @@ measured.
|
||||||
|
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\begin{tabular}{rrrr}
|
\begin{tabular}{rrrr}
|
||||||
array size $n$ & algorithm 1 & algorithm 2 & algorithm 3 \\
|
array size $n$ & Algorithm 1 & Algorithm 2 & Algorithm 3 \\
|
||||||
\hline
|
\hline
|
||||||
$10^2$ & $0{,}0$ s & $0{,}0$ s & $0{,}0$ s \\
|
$10^2$ & $0{,}0$ s & $0{,}0$ s & $0{,}0$ s \\
|
||||||
$10^3$ & $0{,}1$ s & $0{,}0$ s & $0{,}0$ s \\
|
$10^3$ & $0{,}1$ s & $0{,}0$ s & $0{,}0$ s \\
|
||||||
|
|
Loading…
Reference in New Issue