整数の配列 nums
と整数 target
が与えられたとき、その和が target
になるような2つの数値のインデックスを返します。
各入力には正確に一つの解が存在すると仮定してよく、同じ要素を二回使用することはできません。
答えはどのような順序で返しても構いません。
例 1:
入力: nums = [2,7,11,15], target = 9
出力: [0,1]
説明: nums[0] + nums[1] == 9
となるため、[0, 1]
を返します。
例 2:
入力: nums = [3,2,4], target = 6
出力: [1,2]
例 3:
入力: nums = [3,3], target = 6
出力: [0,1]
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order.
Example 1:
Input: nums = [2,7,11,15]
, target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9
, we return [0, 1]
.
Example 2:
Input: nums = [3,2,4], target = 6
Output: [1,2]
Example 3:
Input: nums = [3,3], target = 6
Output: [0,1]
この文書では、プログラミングで一般的な「Two-Sum問題」を解く二つのアプローチについて説明します。また、後者のハッシュマップを使用した方法がなぜ初めの方法よりも優れているかを解説します。
func twoSum(nums []int, target int) []int {
for i := 0; i < len(nums); i++ {
for j := i + 1; j < len(nums); j++ {
if nums[i]+nums[j] == target {
return []int{i, j}
}
}
}
return nil
}
この方法では、すべての要素の組み合わせを総当りで調べています。配列 nums
の各要素 i
に対して、i
より後の要素 j
をループさせ、それぞれの和が target
と等しいかどうかを確認します。このアプローチは直感的で理解しやすいですが、時間計算量が (O(n^2)) となり、大きなデータセットでは非効率的です。
package main
import "fmt"
func twoSum(nums []int, target int) []int {
numMap := make(map[int]int)
for i, num := range nums {
result := target - num
if _, ok := numMap[result]; ok {
return []int{numMap[result], i}
}
numMap[num] = i
}
return nil
}
func main() {
nums := []int{2, 7, 11, 15}
target := 9
fmt.Println(twoSum(nums, target)) // 出力: [0, 1]
}
#### 解説
この方法では、map
データ構造を利用して各数字とそのインデックスを保存し、計算を進めることで効率よく解を見つけます。各ステップで target
から現在の数値を引いた結果が map
に既に存在するかどうかを確認します。この手法では時間計算量が (O(n)) と大幅に改善され、大規模なデータに対しても高速に動作する。
データ構造におけるデータ探索の効率性は、アプリケーションのパフォーマンスに直接的な影響を与える。ここでは、Hashmapと配列を使用したデータ探索の違いを例を挙げて詳細に解説する。
配列はデータを連続したメモリスペースに格納するデータ構造であり、インデックスを用いたアクセスが可能である。インデックスが既知であれば、そのデータへのアクセスは (O(1)) で非常に高速である。しかし、特定の値を探索する場合、その値の位置がわからない限り、配列の最初から順に値を確認する必要がある。
10万個の要素が格納された配列において、特定の値「523」を見つけるためには、最悪の場合10万回の比較が必要となる。これは時間計算量が (O(n)) であり、データ量が多い場合に非効率である。
Hashmapはキーと値のペアを格納するデータ構造であり、キーに対応する値へのアクセスを高速化するための最適化が施されている。Hashmapはハッシュ関数を使用してキーから直接インデックスを計算し、そのインデックスを使って値へアクセスする。このプロセスは平均して (O(1)) の時間計算量で行われる。
10万個のキーと値が格納されたHashmapにおいて、キー「523」の値を探索する場合、ハッシュ関数がこのキーを直接インデックスに変換し、一回のアクセスで値を見つけ出すことができる。この効率的なアクセスは、大規模なデータセットにおいて特に重要である。
配列では、値への直接アクセスにはインデックスが必要であり、値を探索するためには全ての要素を確認する必要があるため、時間がかかる。一方、Hashmapはキーを通じて即座に値にアクセスできるため、データ探索においてははるかに効率的である。特に動的なデータ構造や大量のデータが扱われる場合に、Hashmapの利用が適している。この理解はソフトウェア開発において、データ構造を適切に選択し、アプリケーションのパフォーマンスを最適化するための重要な基礎となる。
配列は、データが連続的なメモリ領域に格納されるデータ構造であり、インデックスによる直接アクセスが可能であるため、特定の用途において非常に効率的である。以下のような状況では、配列の使用が推奨される。
配列は要素がメモリ内で連続して保持されるため、順序性を保ちやすい。例えば、時間の経過に伴うデータの変化を記録したり、昇順や降順でデータを管理したい場合には、配列が有効である。配列を利用することで、データの並び替えや検索が簡単になり、効率的な処理が可能となる。
配列は固定サイズのデータを効率的にメモリに格納することができる。データのサイズが予めわかっており、動的なサイズ変更が不要な場合には、配列を使用するとメモリの無駄が少なくなる。また、配列はデータの密集度が高く、キャッシュの利用効率も良いため、パフォーマンスが向上する。
リアルタイムシステムでは、予測可能な実行時間が求められる。配列は固定されたメモリ領域にデータを格納し、インデックスによる直接アクセスが可能であるため、アクセス時間が一定であり、リアルタイム処理に適している。音声や映像処理など、データが高速に処理される必要があるアプリケーションでは、配列の利用が理想的である。
プログラムが単純明快であることが求められる初学者向けのプログラミング教育や、アルゴリズムの基本的な学習においては、配列を使用すると、データ構造の理解が容易になる。配列によるデータアクセスは直感的であり、プログラムのトレーシングやデバッグが簡単になるため、教育的な環境では特に推奨される。