Escolar Documentos
Profissional Documentos
Cultura Documentos
01-02
Introduction to
Design and Analysis of Algorithms
Algorithmic Warm-Up
Imran Ihsan
Assistant Professor, Department of Computer Science
Air University, Islamabad, Pakistan
www.imranihsan.com
Problem description
Given a sequence of non-negative integers a0,…,an−1, find the maximum pairwise
product, that is, the largest integer that can be obtained by multiplying two different
elements from the sequence or, more formally,
max aiaj
0≤i≠j≤n−1
2
Input / output
Input
The first line of the input contains an integer n.
The next line contains n non-negative integers a0,…,an−1 (separated by
spaces).
Constraints
2 ≤ n ≤ 2⋅105;
0 ≤ a0,…,an−1 ≤ 105.
Output
Output a single number — the maximum pairwise product.
3
Sample 1
Input:
1. 3
2. 1 2 3
Output:
1. 6
Explanation:
6=2×3
4
Sample 2
Input:
1. 10
2. 7 5 14 2 8 8 10 1 2 3
Output:
1. 140
Explanation:
140 = 14 × 10
5
Starter solution
#include <iostream>
#include <vector>
using std::vector;
using std::cin;
using std::cout;
int MaxPairwiseProduct(const vector<int>& numbers) {
int result = 0;
int n = numbers.size();
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (numbers[i] * numbers[j] > result) {
result = numbers[i] * numbers[j];
}
}
}
return result;
}
int main() {
int n;
cin >> n;
vector<int> numbers(n);
for (int i = 0; i < n; ++i) {
cin >> numbers[i]; }
int result = MaxPairwiseProduct(numbers);
cout << result << "\n";
return 0;
}
6
Test the system
Input:
1. 2
2. 100000 90000
Output:
1. 410065408
Explanation:
Correct Output: 9000000000
Failed Case: Wrong Answer
7
Fixing an integer overflow bug
#include <iostream>
#include <vector>
using std::vector;
using std::cin;
using std::cout;
double MaxPairwiseProduct(const vector<int>& numbers) {
double result = 0;
int n = numbers.size();
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (((double)numbers[i]) * numbers[j] > result) {
result = ((double)numbers[i]) * numbers[j];
}
}
}
return result;
}
int main() {
int n;
cin >> n;
vector<int> numbers(n);
for (int i = 0; i < n; ++i) {
cin >> numbers[i]; }
8
Test again
Input:
1. 2
2. 100000 90000
Output:
1. 9000000000
Explanation:
Correct Answer
9
However system fails again
Our program performs about n2 steps on a sequence of length n.
For the maximal possible value n = 200,000 =2⋅105,
The number of steps is about 10,000,000,000=1010.
This is too much.
Modern machines can perform roughly 109 basic operations per second.
Thus, we need a faster algorithm.
10
Implementing a faster solution
double MaxPairwiseProductFast(const vector<int>& numbers) {
int n = numbers.size();
int max_index1 = -1;
for (int i = 0; i < n; ++i)
if ((max_index1 == -1) || (numbers[i] > numbers[max_index1]))
max_index1 = i;
int main() {
int n;
cin >> n;
vector<int> numbers(n);
for (int i = 0; i < n; ++i) {
cin >> numbers[i];
}
11
Testing
Input:
1. 3
2. 7 2 5
Output:
1. 35
2. 35
Explanation:
Satisfactory
12
Stress Test
while (true) {
int n = rand() % 10 + 2;
cerr << n << "\n";
vector<int> a;
for (int i = 0; i < n; ++i) {
a.push_back(rand() % 100000);
}
if (res1 != res2) {
cerr << "Wrong answer: " << res1 << ' ' << res2 << "\n";
break;
}
else {
cerr << "OK\n";
}
}
13
Run stress test
...
OK
3
67232 68874 69499
OK
8
6132 56210 45236 95361 68380 16906 80495 95298
OK
11
62180 1856 89047 36823 14251 8362 34171 93584 87362 83341 8784
OK
6
21468 16859 82178 70496 82939 44491
OK
11
68165 30342 87637 74297 2904 32873 86010 87637 66131 82858 82935
Wrong answer: 7680243769 7537658370
14
Stress Test – small & simple input
while (true) {
int n = rand() % 4 + 2;
cerr << n << "\n";
vector<int> a;
for (int i = 0; i < n; ++i) {
a.push_back(rand() % 10);
}
if (res1 != res2) {
cerr << "Wrong answer: " << res1 << ' ' << res2 << "\n";
break;
}
else {
cerr << "OK\n";
}
}
15
A faster solution
double MaxPairwiseProductFast(const vector<int>& numbers) {
int n = numbers.size();
int max_index1 = -1;
for (int i = 0; i < n; ++i)
if ((max_index1 == -1) || (numbers[i] > numbers[max_index1]))
max_index1 = i;
5
2 9 3 1 9
1 2
Wrong answer: 81 27
17
A faster solution – correct answer
double MaxPairwiseProductFast(const vector<int>& numbers) {
int n = numbers.size();
int max_index1 = -1;
for (int i = 0; i < n; ++i)
if ((max_index1 == -1) || (numbers[i] > numbers[max_index1]))
max_index1 = i;
18
Fibonacci Series – Definition
19
Developed to Study Rabbit Populations
20
Rapid Growth
Lemma
Fn ≥ 2n/2 for n ≥ 6
Proof
By induction
Base case: n = 6, 7 (by direct computation).
Inductive step:
Fn = Fn−1 + Fn−2 ≥ 2(n−1)/2 + 2(n−2)/2
≥ 2·2(n−2)/2 = 2n/2
21
Formula
22
example
F20 = 6765
F50 = 12586269025
F100 = 354224848179261915075
F500 = 1394232245616978801397243828
7040728395007025658769730726
4108962948325571622863290691
557658876222521294125
23
Naïve Algorithm
FibRecurs(n)
if n ≤ 1:
return n
else:
return FibRecurs(n−1) + FibRecurs(n−2)
Running Time
Let T(n) denote the number of lines of code
executed by FibRecurs(n).
24
Running time
FibRecurs(n)
if n ≤ 1:
return n
else:
return FibRecurs(n−1) + FibRecurs(n−2)
If n ≤ 1: T(n) = 2
If n ≥ 2: T(n) = 3 + T(n − 1) + T(n − 2)
25
Running time
T(n) = 2 if n ≤ 1
T(n − 1) + T(n − 2) + 3 else
Therefore: T(n) ≥ Fn
T(100) ≈ 1.77 · 1021
(1.77 sextillion)
26
Why so slow?
27
Why so slow?
28
Why so slow?
29
Why so slow?
30
Efficient algorithm
31
Another Algorithm
Imitate hand computation:
0, 1, 1, 2, 3, 5, 8
0 + 1 = 1
1 + 1 = 2
1 + 2 = 3
2 + 3 = 5
3 + 5 = 8
32
New Algorithm
FibList(n)
create an array F [0 . . . n]
F[0] ← 0
F[1] ← 1
for i from 2 to n:
F[i] ← F[i−1] + F[i−2]
return F[n]
33
GCD
𝑎
Put fraction in simplest form.
𝑏
𝑎/𝑑
Divide numerator and denominator by d, to get
𝑏/𝑑
Need d to divide a and b.
Want d to be as large as possible
Greatest Common Divisor
For integers, a and b, their greatest common
divisor or gcd(a, b) is the largest integer d
so that d divides both a and b.
Number Theory
Cryptography
Computation
Compute GCD
Input: Integers a,b 0
Output: gcd(a,b)
Runtime approximately a + b.
Very slow for 20 digit numbers
Lemma
Let a′ be the remainder when a is divided by b, then
Example:
gcd(3918848, 1653264)
= gcd(1653264, 612320)
= gcd(612320, 428624)
= gcd(428624, 183696)
= gcd(183696, 61232)
= gcd(61232, 0)
= 61232
Runtime
Each step reduces the size of numbers by about a factor of 2.