今是昨非

今是昨非

日出江花红胜火,春来江水绿如蓝

アルゴリズム_二つのポインタ

アルゴリズム_TwoPointers#

Two Sum II - Input Array Is Sorted#

既に非減少順にソートされた 1 から始まる整数の配列 numbers が与えられ、特定の目標数に合計できる 2 つの数を見つけます。これらの 2 つの数を numbers [index1] と numbers [index2] とし、1 <= index1 < index2 <= numbers.length とします。

長さ 2 の整数配列 [index1、index2] として、2 つの数のインデックス、index1 と index2 を 1 つずつ追加して返します。

テストは正確に 1 つの解があるように生成されます。同じ要素を 2 回使用することはできません。

あなたの解決策は、定数の余分なスペースのみを使用する必要があります。

例 1:

Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: 2と7の合計は9です。したがって、index1 = 1、index2 = 2です。[1, 2]を返します。

例 2:

Input: numbers = [2,3,4], target = 6
Output: [1,3]
Explanation: 2と4の合計は6です。したがって、index1 = 1、index2 = 3です。[1, 3]を返します。

例 3:

Input: numbers = [-1,0], target = -1
Output: [1,2]
Explanation: -1と0の合計は-1です。したがって、index1 = 1、index2 = 2です。[1, 2]を返します。

解法一#

直接遍歴し、二重の for ループを使用しますが、i != j です。

コードは以下の通りです:


class Solution {
    func twoSum(_ numbers: [Int], _ target: Int) -> [Int] {
        var indexList: [Int] = []
        for i in 0..<numbers.count {
            for j in (i+1)..<numbers.count {
                if numbers[i] + numbers[j] == target {
                    indexList.append(i+1)
                    indexList.append(j+1)
                    break
                }
            }
            if indexList.count > 0 {
                break
            }
        }
        return indexList
    }
}

しかし、上記の方法はアルゴリズムとは言えませんので、最適化が必要です。配列がソートされているため、index=0 の場所が最小であり、index=count-1 の場所が最大です。TwoPointer のアプローチを使用する必要があります。つまり、2 つの変数を定義し、先頭と末尾から同時に開始し、head+tail>target の場合、tail を減らして前に移動し、head+tail<target の場合、head を増やして後ろに移動します。head+tail が結果と等しい場合、返します。

コードは以下の通りです:


class Solution {
    func twoSum(_ numbers: [Int], _ target: Int) -> [Int] {        
        var i = 0;
        var j = numbers.count - 1;
        
        while (i < j) {
            let small = numbers[i]
            let big = numbers[j]
            if small + big == target {
                break
            }
            else if small + big < target {
                i += 1
            }
            else {
                j -= 1
            }
        }
        return [i+1, j+1]
    }
}

解法二#

このアプローチは、辞書の機能を利用しています。辞書のキーは配列の値であり、値は配列のインデックスです。次に、配列を反復処理し、target-num の値が辞書にある場合は、[dic [target-num] + 1、index] を返します。辞書にない場合は、{num: index} を辞書に保存します。配列がソートされているため、小さい順に反復処理されるため、結果が見つかった場合、返される順序辞書の値に対応するインデックスは小さいため、最初の要素です。

コードは以下の通りです:


class Solution {
    func twoSum(_ numbers: [Int], _ target: Int) -> [Int] {
        var dic: [Int: Int] = [:]
        for index in 0..<numbers.count {
            let num = numbers[index]
            if dic.keys.contains(target-num) {
                return [dic[target-num]! + 1, index+1]
            }
            else {
                dic[num] = index
            }
        }
        return []
    }
}

解法三#

このアプローチは、BinarySearch アプローチを使用しています。ロジックは、配列を反復処理し、各反復で target と現在の数字の差を取得し、行う必要があるのは、配列の後の要素にその差が存在するかどうかを検索することです。存在する場合は、対応するインデックスを返し、存在しない場合は次の反復を続けます。

コードは以下の通りです:


class Solution {
    func twoSum(_ numbers: [Int], _ target: Int) -> [Int] {        
        for i in 0..<numbers.count {
            let num = numbers[i]
            let tmp = target - num
            // そして、binarySearchを使用してtmpと等しい要素があるかどうかを検索します
            var l = i + 1
            var r = numbers.count - 1
            var middle = 0
            while (l <= r) {
                middle = l + (r - l) / 2
                if numbers[middle] == tmp {
                    return [i+1, middle+1]
                }
                else if numbers[middle] < tmp {
                    l += 1
                }
                else {
                    r -= 1
                }
            }
        }
        return []
    }   
}

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。