Let A be a sorted array of integers and S a target integer.
Design an efficient algorithm for determining if there exist
a pair of indices i,j (not ncessarily distinct) such that A[i] + A[j] = S.
( Algorithms for interview より引用 )
ヒント
sorted array .. 2分探索?2分探索でも勿論解ける.しかしバイナリサーチより効率の良いアルゴリズムは?
解答1
適当にループで回してもO(N^2)で解を出すことはできるが,もう一工夫.
バイナリサーチで検索の範囲を狭めれば良くてO((N/2)^2),悪くてO(N^2)となる.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
void init_vector(vector<int>& v) {
v.push_back( 5 );
v.push_back( 8 );
v.push_back( 12 );
v.push_back( 20 );
v.push_back( 33 );
v.push_back( 45 );
v.push_back( 53 );
v.push_back( 64 );
v.push_back( 80 );
}
int search_max(const vector<int>& v, int s) {
int min = 0;
int max = v.size() - 1;
int mid;
int midval;
bool found = false;
// pre .. if s is less than v[0], no way to find pair.
if( s <= *(v.begin()) )
throw "not qualify pre-requisite";
while( min <= max ) {
mid = (min + max) / 2;
midval = v.at(mid);
if( s == midval ) {
found = true;
break;
}
else if( s > midval) {
min = mid + 1;
}
else {
max = mid - 1;
}
}
return found ? mid : max;
}
bool search(const vector<int>& v, int s) {
int max;
try {
max = search_max(v,s);
cout << "max for search:" << max << endl;
}catch(const char* msg) {
cerr << "errmsg:" << msg << endl;
return false;
}
for( int i = 0;i < max;i++ ) {
for( int j = i;j < max;j++ ) {
if( v[i] + v[j] == s )
return true;
}
}
return false;
}
void dump(const vector<int>& v) {
for( vector<int>::const_iterator iter = v.begin();iter != v.end();iter++ ) {
cout << *iter << endl;
}
}
int main()
{
vector<int> v;
init_vector(v);
dump(v);
try {
cout << search(v,3) << endl;
} catch( const char* err) {
cerr << err << endl;
}
cout << search(v,55) << endl;
cout << search(v,53) << endl;
return 0;
}
解答2
プログラムは長くなった割に得たものは少ない.ならばアプローチを変えよう. 目的の数Sからループ中の要素v[i]を引いてcを得る.そのcがハッシュテーブルにあれば(O(1)オーダで検索可),v[i]+v[j]=Sを満たすのである. プログラムは非常にすっきりするし,オーダもO(N)である.
bool search2(const vector<int>& v, int s ) {
map<int,int> m;
vector<int>::const_iterator iter;
int c;
int i;
for(i = 0,iter = v.begin();iter != v.end();iter++,i++) {
c = s - v[i];
m[v[i]] = i;
if( m.find( c ) != m.end() )
return true;
}
return false;
}
0 件のコメント:
コメントを投稿