1. 問題の説明:
n (n>=1) 個の整数を含む配列が与えられた場合、配列内に現れない最小の正の整数を見つけるためにできるだけ時間効率の良いアルゴリズムを設計してください。たとえば、配列 {-5, 3, 2, 3} に現れない最小の正の整数は 1 で、配列 {1, 2, 3} に現れない最小の正の整数は 4 です。は:
- アルゴリズムの基本的な設計アイデアを示します。
- 設計思想に沿ってアルゴリズムをC言語またはC++言語で記述し、要点をコメントします。
- 設計したアルゴリズムの時間計算量と空間計算量を説明します。
2. アルゴリズム的思考:
時間的にはできるだけ効率的であることが求められるため、空間と時間を交換するという手法がとられます。 A に 1 から n までの正の整数が出現するかどうかを記録するためのマーク用の配列 B[n] を割り当てます。B[0] は正の整数 1 に対応し、B[n-1] は正の整数 n に対応します。 B を初期化します。全て0です。 A には n 個の整数が含まれているため、返される可能性のある値は 1 ~ n+1 です。A に含まれる n 個の数値がちょうど 1 ~ n の場合、n+1 が返されます。0 以下の整数またはそれ以上の整数がある場合は、n+1 が返されます。配列 A の n よりも大きい値が設定された場合、1 ~ n には空き位置があり、返される結果は 1 ~ n になければなりません。したがって、0 以下の値または n より大きい値が配列 A に現れた場合、 A、対処はできません。
上記の分析の後、アルゴリズム フローを描くことができます: A[0] から開始して A を通過します。0
3. アルゴリズムコード:
int findMissMin(int A[],int n)
{
int i,*B;//标记数组
B = (int *)malloc(sizeof(int) * n);//分配空间
memset(B,0,sizeof(int) * n);//赋初值为0
for(i = 0;i < n;i++)
{
if(A[i] > 0 && A[i] <= n)//若A[i]的值介于1~n,则标记数组B
B[A[i] - 1] = 1;
}
for(i = 0;i < n;i++)//扫描数组B,找到目标值
{
if(B[i] == 0)
break;
}
return i + 1;//返回结果
}
4. アルゴリズムの複雑さ:
- 時間計算量: A を 1 回トラバースし、B を 1 回トラバースします。2 つのループの演算ステップは O(1) 程度であるため、時間計算量は O(n) です。
- 空間複雑度: B[n] が追加で割り当てられ、空間複雑度は O(n) になります。
5. memset 関数を拡張します。
C ライブラリ関数 void *memset(void *str, int c, size_t n) は、文字 c (符号なし文字) を、パラメータ str が指す文字列の最初の n 文字にコピーします。
パラメータ:
- str – 埋められるメモリ ブロックへのポインタ。
- c – 設定する値。値は int として渡されますが、関数はメモリ ブロックを埋めるときに値の符号なし文字形式を使用します。
- n – この値に設定される文字数。
戻り値:
- 値は記憶領域 str へのポインタを返します。
memset に値を割り当てる場合、値 0 のみを割り当てることができます。
- たとえば、任意の文字を使用できますが、0 に初期化することが最も一般的に使用されます。一般に、int 型には 0 または -1 の値が割り当てられ、他の値は受け入れられません。