Skip to content

Conversation

@syoshida20
Copy link
Owner

@syoshida20 syoshida20 commented May 6, 2025

問題URL

https://leetcode.com/problems/intersection-of-two-arrays/

問題文

Given two integer arrays nums1 and nums2, return an array of their intersection. Each element in the result must be unique and you may return the result in any order.

Example 1:

  • Input: nums1 = [1,2,2,1], nums2 = [2,2]
  • Output: [2]

Example 2:

  • Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
  • Output: [9,4]
  • Explanation: [4,9] is also accepted.

Constraints:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000

@syoshida20 syoshida20 marked this pull request as ready for review May 6, 2025 13:06
};
```

* `*2` Setのintersection関数を使用した方法
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こういうのリファレンスへのリンクを張っておくといいと思います。
(調べる癖をつけるのはわりと重要と思っています。そして、知らないメソッドが生えていたりします。)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。自分自身が足りていない箇所なので、人よりも多く調べる量を増やそうと思います。

}
const common = nums1[i]
result.push(common)
while (nums1[i] === common && i < nums1.length) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これ、左右逆にしないと、範囲外アクセスをする恐れがありませんか? JavaScript はいいんでしたっけ。

Copy link
Owner Author

@syoshida20 syoshida20 May 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JavaScriptだと範囲外にアクセスをした際には、undefinedが返ってくるというので、上のコード自体は問題がなかったです。

しかし、自分の方がその恐れを認識した上で、コードを書けていませんでした。ご指摘ありがとうございます。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらにて、コードを追加しました! a0dc7df

* 両方が大きい場合
* メモリの制約がある場合、Two Pointerを用いて解く。
空間計算量が O(1)
時間計算量が O(N log N)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

正しくは、O(N log N + M log M)

continue
}
ans.push(num2)
is_num_appeared.set(num2, false)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_num_appeared.delete(num2) とすると || is_num_appeared.get(num2) === false が消せると思いました。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mapのvalue(boolean)で存在の確認をするのではなく、
Mapのkeyで存在の確認をするということですね。

勉強になります。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d26a976 にて、コードを追加しました。

const ans = []
while (!next.done) {
const num1 = next.value
let left = 0
Copy link

@nodchip nodchip May 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

念のため確認させてください。

  • 二分探索の問題をどのような問題として捉えていますか?典型的な捉え方にはどのようなものがありますか?
  • 閉区間・開区間・半開区間の違いを説明してみてください。
  • ループの不変条件=ループが回っているあいだ、成立しつづける条件は何ですか?
  • どのような状態になったときにループを抜けますか?
  • ループが回っているあいだ、区間の中にはどのような要素が含まれていますか?区間の左端より左にはどのような要素が含まれていますか?区間の右端より右にはどのような要素が含まれていますか?
  • left = middle とすると動きますか?動くとしたらなぜですか?動かないとしたらなぜですか?
  • right = middle とすると動きますか?動くとしたらなぜですか?動かないとしたらなぜですか?

Copy link
Owner Author

@syoshida20 syoshida20 May 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

二分探索の問題をどのような問題として捉えていますか?典型的な捉え方にはどのようなものがありますか?

ソート済みの配列が与えられた際に、探索範囲を半分ずつ絞っていくことで、以下のような問いを効率的に探索する問題。

  1. 重複のない配列で、ある数字が含まれているかどうかを求める
  2. 重複のない配列で、境界を求める

ある数字がソート済みの配列に含まれているかどうか? を最初に考え、
境界を求めるケースを次に考える。

ある数字が含まれているかどうか

閉区間・開区間・半開区間の違いを説明してみてください。

閉区間 : a <= x <= b
開区間 : a < x < b
半開区間 : a <= x < b、または、 a < x <= b

(閉区間の場合)

// 引き継ぎ条件 :
// left <= target <= right
while () {
    if (middle === right) {
        return true
    }
    if (middle < right) {
        left = middle + 1
        continue
    }
    right = middle - 1
}

(開区間の場合)

// 引き継ぎ条件 :
// left < target < right
while () {
    if (middle === right) {
        return true
    }
    if (middle < right) {
        left = middle
        continue
    }
    right = middle
}

(半開区間)
以下のどちらかの代入を行った時

  • left = middle + 1, right = middle --> left <= target < right
  • left = middle, right = middle - 1 --> left < target <= right

ループの不変条件=ループが回っているあいだ、成立しつづける条件は何ですか?

閉区間の場合、left <= target <= right、targetが1つ以上存在すること ( <==> left <= rightであること )
開区間の場合、left < target < rightで、targtが1つ以上存在すること( <==> left < rightであること)

どのような状態になったときにループを抜けますか?

値が見つかった時( middle == targetの時)
値が見つからなかった時、

  • 閉区間の場合には、right < left
  • 開区間の場合には、right <= left

ループが回っているあいだ、区間の中にはどのような要素が含まれていますか?区間の左端より左にはどのような要素が含まれていますか?区間の右端より右にはどのような要素が含まれていますか?

  • 区間の中には、
    • left <= target <= right(閉区間の場合)、
    • left < target < right(開区間の場合)、
  • 区間の左側には、targetより小さい値が含まれている。
  • 区間の右側には、targetより大きい値が含まれている。

left = middle とすると動きますか?動くとしたらなぜですか?動かないとしたらなぜですか?

動かない。なぜなら、targetが半分よりも左側に含まれている際に、探索対象を右半分に絞った初期状態で探索が開始されてしまうから。

right = middle とすると動きますか?動くとしたらなぜですか?動かないとしたらなぜですか?

動かない。なぜなら、targetが半分よりも右側に含まれている際に、探索対象を左半分に絞った初期状態で探索が開始されてしまうから。

境界を求める場合

  • ループの不変条件が異なる。

開区間または、半開区間を用いる必要がある。

  • while文の中で、x<=aとa<x、または、x<aとa<=x の比較のみで十分である。

先ほどは、==の場合、<の場合、>の場合の3通りを調べていた。

Copy link

@nodchip nodchip May 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。おおよそ大丈夫だと思います。他の捉え方をしている方もいますので、過去のレビューコメント等を参考に、その方々の捉え方を調べても良いと思います。

重複のない配列で、ある数字が含まれているかどうかを求める
重複のない配列で、境界を求める

重複がある配列でも求めることができると思います。

また、実装方法についても

ある数字が含まれているかどうか

については、ループを抜けた段階で、区間の中に、ある数字以上かつ最小の値の中で、一番左の数字のみが含まれた状態にし、その数字がある数字かどうかを判定するという方法もあります。この場合、 if (middle === right) { を入れても入れなくても動きます。

値が見つからなかった時、
開区間の場合には、right <= left

これは合っていますでしょうか?

left = middle とすると動きますか?動くとしたらなぜですか?動かないとしたらなぜですか?
動かない。なぜなら、targetが半分よりも左側に含まれている際に、探索対象を右半分に絞った初期状態で探索が開始されてしまうから。

ここ、おそらく質問文が曖昧でした。申し訳ありません。「left = middle + 1 の代わりに left = middle とすると動きますか?動くとしたらなぜですか?動かないとしたらなぜですか? 」でした。

境界を求める場合
ループの不変条件が異なる。
開区間または、半開区間を用いる必要がある。

閉区間でも求めることができます。これについても過去のレビューコメントを探してみるとよいと思います。

最終的に、自分なりに二分探索を理解し、理解に基づき実装できでば十分だと思います。また、ほかの方の二分探索の捉え方を理解でき、その実装も理解できればより良いのだと思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants