アルゴリズムの設計と分析のための戦略演習を分割して征服する
問題1を解決するために戦略を分割して征服する:半分に検索する
問題の説明
昇順でソートされたn個の要素a [0:n-1]が与えられた場合、これらのn個の要素の中から特定の要素xを見つけたいと思います。
問題分析
要素の中央から検索を開始し、連続的に半分にしてxを検索すると、半分に検索するためのサブ問題は互いに独立しています。
アルゴリズムの実装
//折半查找递归实现
int binarySearch(int a[],int left,int right,int x){
if(left<=right){
int middle = (left + right) / 2;
if(x == a[middle]) return middle;
else if(x < a[middle]) return binarySearch(a,left,middle-1,x);
else return binarySearch(a,middle+1,right,x);
}
return -1; //没找到返回-1
}
問題2を解決するために戦略を分割して征服する:バイナリ検索テクノロジーアプリケーション1
問題の説明
整数の数が与えられると、数値の組の合計が所定数に等しい場合に尋ねる。
入力:
4
2 5 1 4
6
出力
1~5
説明:要件を満たす数値の複数の対がある場合の出力と対最小数は
問題分析
- 最初に配列を小さいものから大きいものに並べ替えます
- 前者に対応する値を見つけるためにバイナリ検索を使用する
- 見つかったら検索を停止します。それ以外の場合は続行します
アルゴリズムの実装
//折半查找递归实现
int binarySearch(int a[],int left,int right,int x){
if(left<=right){
int middle = (left + right) / 2;
if(x == a[middle]) return middle;
else if(x < a[middle]) return binarySearch(a,left,middle-1,x);
else return binarySearch(a,middle+1,right,x);
}
return -1; //没找到返回-1
}
void SumNumberSearch(int a[],int length,int sum){
for(int i=0;i<length;i++){
if(binarySearch(a,i+1,length-1,sum-a[i])){
cout<<a[i]<<" "<<sum-a[i];
break;
}
}
}
問題3を解決するための戦略を分割して征服する:バイナリ検索テクノロジーアプリケーション2
問題の説明
n個の数字を入力し、小さいものから大きいものへと出力し、繰り返し番号を1回だけ出力します。
入力:
5
2 4 4 5 1
出力:
1 2 4 5
問題分析
最も簡単な方法は、setを使用し、setの性質を使用することです。ここでは、バイナリ検索テクノロジを使用して、この方法を使用しません。
- まず、配列を小さいものから大きいものに並べ替えます
- 真ん中の番号から始めて、番号の最初と最後の出現をそれぞれ記録します
- 同じ方法で左側のサブシーケンスを分析します
- 数値を出力
- 同じ方法で正しいサブシーケンスを分析します
アルゴリズムの実装
void lineSearch(int a[],int left,int right){
int number,middle,l,r,i;
if(left>right) return;
middle = (left + right)/2;
number = a[middle];
i = middle - 1;
while(a[i]==number && i>=left) i--;
l = i;
i = middle + 1;
while(a[i]==number && i<=right) i++;
r = i;
lineSearch(a,left,l);
cout<<number<<" ";
lineSearch(a,r,right);
}
問題4を解決するために戦略を分割して征服する:モードと多様性
問題の説明
n個の自然数からなる与えられた複数の数のセットSについて、Sのモードと多重度を計算するプログラム
問題分析
- アレイストレージを使用する
- 最初に配列を並べ替えます
- ミドルナンバーのインデックス、ミドルナンバーの出現回数、ミドルナンバーの最初の出現位置を記録します
- 中間数の多重度を前のレコードの多重度と比較します。前のレコードの多重度よりも大きい場合は、numとsumを更新します。
- 最大の多重度が中央の数字の右側の桁数よりも小さい場合は、右側の再帰分析
- 最大の多重度が中央の数字の左側の桁数よりも小さい場合は、左側を再帰的に分析します
アルゴリズムの実装
#include <iostream>
#include <algorithm>
#define N 100
using namespace std;
int num = 0; //存储众数
int sum = 0; //存储重数
/*
统计中间数出现的数量
*/
int count(int[],int,int);
/*
找到中间数第一次出现的位置
*/
int start(int[],int,int);
/*
找众数和其重数
*/
void modeAndMultiplicity(int[],int,int);
int main()
{
int a[N],n;
cout<<"请输入数组元素数量:";
cin>>n;
cout<<"请输入数组元素:";
for(int i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
modeAndMultiplicity(a,0,n-1);
cout<<"众数"<<num<<"的重数为"<<sum<<endl;
return 0;
}
/*
统计中间数出现的数量 实现
*/
int count(int a[],int front,int rear){
int i = 0; //计数器
int mid = a[(front+rear)/2];
for(int j=front;j<=rear;j++){
if(a[j] == mid){
i++;
}
}
return i;
}
/*
找到中间数第一次出现的位置 实现
*/
int start(int a[],int front,int rear){
int x = 0;
int mid = a[(front+rear)/2];
for(int i=front;i <= rear;i++){
if(a[i] == mid){
x = i;
break;
}
}
return x;
}
/*
找众数和其重数 实现
*/
void modeAndMultiplicity(int a[],int front,int rear){
int mNum = (front+rear)/2; //当前中间数的下标
int mSum = count(a,front,rear); //当前中间数的重数
int mLeft = start(a,front,rear); //当前中间数第一次出现的位置
if(mSum > sum) {
//重数大则替换众数和其重数
sum = mSum;
num = a[mNum];
}
if(rear-(mLeft+mSum)+1 > sum){
//右边数量大于重数 则向右找
modeAndMultiplicity(a,mLeft+mSum,rear);
}
if(mLeft > sum){
//左边数量大于重数 则向左找
modeAndMultiplicity(a,front,mLeft-1);
}
}
問題5を解決するための戦略を分割して征服する:インターバルマージ
問題の説明
n個の閉じた間隔[ai; bi]が与えられます。ここで、i = 1,2、...、nです。隣接または交差する2つの閉じた間隔は、1つの閉じた間隔にマージできます。たとえば、[1; 2]と[2; 3]は[1; 3]に結合でき、[1; 3]と[2; 4]は[1; 4]に結合できます。つまり[1; 2]と[ 3; 4]マージできません。
これらの間隔を最終的に閉じた間隔にマージできるかどうかを判断します。マージできる場合は閉じた間隔を出力し、そうでない場合はいいえを出力します。
問題分析
- ストレージの間隔構造を定義し、比較機能を定義します
- 入力間隔グループを並べ替えた後、2つの小さな領域間のマージの問題になるまで、左側と右側で分割して征服します。
- 組み合わせることができない場合、プログラムはnoを出力し、直接終了します
- 可能であれば、除算の終了後に結果をマージし、征服して最終的な間隔を取得します
アルゴリズムの実装
#include <iostream>
#include <algorithm>
//定义区间数量
#define N 100
using namespace std;
//定义区间结构体
struct Interval{
int left,right;
};
//定义区间比较函数
bool compareInterval(Interval,Interval);
//区间合并
Interval intervalMerge(Interval[],int,int);
int main()
{
Interval interval[N];
int n;
cout<<"请输入区间数量:";
cin>>n;
for(int i=0;i<n;i++)
cin>>interval[i].left>>interval[i].right;
sort(interval,interval+n,compareInterval);
Interval tempInterval = intervalMerge(interval,0,n-1);
cout<<tempInterval.left<<" "<<tempInterval.right<<endl;
return 0;
}
bool compareInterval(Interval mLeft,Interval mRight){
if(mLeft.left < mRight.left)
return true;
return false;
}
Interval intervalMerge(Interval internal[],int left,int right){
if(left == right)
return internal[left];
Interval tempInterval1 = intervalMerge(internal,left,(left+right)/2),
tempInterval2 = intervalMerge(internal,(left+right)/2+1,right);
if(tempInterval1.right >= tempInterval2.left){
//符合合并条件 进行合并
Interval tempInterval;
tempInterval.left = tempInterval1.left;
tempInterval.right = tempInterval1.right>=tempInterval2.right
?tempInterval1.right
:tempInterval2.right;
return tempInterval;
}else{
//否则退出
cout<<"no"<<endl;
exit(0);
}
}