元の質問は2つの整数のソートされていないリストのリストを持っています。この問題レットの入力だけを考える簡素化するためには、整数と整数ターゲットの2つのソート配列です。以上1溶液のペアが存在する場合、値のペアを繰り返すことができます。
例えば:[7,8,14]、[5,10,14]ターゲット:20溶液は、20に最も近い二番目の配列の合計19から第一のアレイおよび5から[14]、[5] 14としてあります。
私の解決策は終了し、新たな差が小さい場合に追跡最小差と更新と比較し始めてから、両方の配列をループしました。
しかし、これは強引です。任意のより良い解決策はありますか?
私はオンラインで見つけるほとんどのソリューションは、同じ配列からターゲットを見つけることだった、2つの配列の対象問題と1つのアレイ間のいずれかの類似点はありますか?
一つのキー洞察:合計目標よりも高い対(X、Y)が与えられると、その和が近い任意の対(X、Y「)、Y」> yの合計よりも大きいです。逆に、(x、y)の和が目標よりも低い場合、その和が近い任意の対の和(X「Y)ここで、x」<Xよりなります。
これは、線形時間でアルゴリズムが得られます。
- リストXとYリストの最後の要素の最初の要素を開始します
- それは(もしそうなら、それを覚えて)これまでの最高のペアだかどうかをチェック
- その合計が目標より小さい場合、その合計は、Yの次の下位要素へ移動目標よりも大きい場合にはXの次に高い要素へ移動
- ループは、手順2 - 3あなたはXまたはYの要素を使い果たすまで
Javaでは:
private static Pair<Integer, Integer> findClosestSum(List<Integer> X, List<Integer> Y, int target) {
double bestDifference = Integer.MAX_VALUE;
Pair<Integer, Integer> bestPair = null;
int xIndex = 0;
int yIndex = Y.size() - 1;
while (true) {
double sum = X.get(xIndex) + Y.get(yIndex);
double difference = Math.abs(sum - target);
if (difference < bestDifference) {
bestPair = new Pair<>(X.get(xIndex), Y.get(yIndex));
bestDifference = difference;
}
if (sum > target) {
yIndex -= 1;
if (yIndex < 0) {
return bestPair;
}
} else if (sum < target) {
xIndex += 1;
if (xIndex == X.size()) {
return bestPair;
}
} else {
// Perfect match :)
return bestPair;
}
}
}
あなたは、このアルゴリズムが始まる段落のロジックを通して徹底的であることを証明することができます。任意のペアのためにされなかった訪問し、その2つの要素の一つを含むペアが存在する必要がありました訪問し、その厳密に近いターゲットに合計を持っています。
EDIT:あなただけの、同じロジックがまだ適用され、ターゲット(これらのオーバーシュートではない)よりも少ない金額をしたい場合。オーバーシュートの場合に、(X、Y ')(X、Y)と同じように無効であり、したがって、より良好な候補和することができません。この場合、唯一のそれは、これまでに最も近い非超過合計だ場合にのみ、合計値を保存するために、2ニーズを変更するステップ。