Conversation
| // 入力のデータ型がi32と固定長なので、HashSet作成時の時間計算量はO(1) | ||
| if nums1.len() <= nums2.len() { | ||
| linear_search_base = nums1; | ||
| others = HashSet::from_iter(nums2); | ||
| } else { | ||
| linear_search_base = nums2; | ||
| others = HashSet::from_iter(nums1); | ||
| } |
There was a problem hiding this comment.
入力のデータ型がi32と固定長なので、単一要素のハッシュ計算はO(1)、HashSetの構築はO(n)、だと思ったんですが、どうでしょうか。
There was a problem hiding this comment.
ありがとうございます。ご指摘頂いたとおりです。
計算量の見積もりが苦手で勘違いしたままの記述が残っていました。
| pub struct Solution {} | ||
| impl Solution { | ||
| pub fn intersection(nums1: Vec<i32>, nums2: Vec<i32>) -> Vec<i32> { | ||
| let mut intersected = HashSet::<_>::with_capacity(nums1.len().min(nums2.len())); |
There was a problem hiding this comment.
ありがとうございます。直後の行でifによりminを算出しているので、同じ判定をメソッド内で繰り返してしまっていると理解しました。
| let mut intersected = HashSet::<_>::with_capacity(nums1.len().min(nums2.len())); | |
| let (smaller_nums, larger_nums, mut intersected) = if nums1.len() <= nums2.len() { | |
| ( | |
| &nums1, | |
| HashSet::<_>::from_iter(nums2), | |
| HashSet::with_capacity(nums1.len()), | |
| ) | |
| } else { | |
| ( | |
| &nums2, | |
| HashSet::<_>::from_iter(nums1), | |
| HashSet::with_capacity(nums2.len()), | |
| ) | |
| }; |
|
|
||
| 他の想定ユースケース | ||
| - | ||
| - なぜbinary_searchを使っているのか、HashSet自体は使っているのに、filterでの重複判定に使っている理由などよくわからなかった。 |
There was a problem hiding this comment.
これはnums1のサイズが小さくnums2が比較的大きいがソートはされているという条件のもとで解くとしたら、こういう解き方もあるねという話だと思います。
以下のコメントログも参考になりそうです。
katataku/leetcode#12 (comment)
|
|
||
| // 入力のデータ型がi32と固定長なので、HashSet作成時の時間計算量はO(1) | ||
| if nums1.len() <= nums2.len() { | ||
| linear_search_base = nums1; |
There was a problem hiding this comment.
長さが短い方の配列をイテレートしたいということであれば以下のイメージで引数を入れ替えて関数を呼びなおすという書き方もいいかもしれません。
※rustのことをよく分かっていないので雰囲気で書いてます。
if nums1.len() < nums2.len() {
return intersection(nums2, nums1);
}There was a problem hiding this comment.
ありがとうございます。ご指摘いただ方針でだいぶすっきり書けるなと思いました。
最初見たときに再帰呼び出しをあまりカジュアルに使うべきではないかなとも思ったのですが
- 最悪でも一度しか呼び出さない
- メソッド先頭でガード節で書いておけば、再帰関数呼び出し時に余計なデータがスタックフレームに含まれない
といった理由からパフォーマンスなどの制約から関数呼出しをなるべく行わないといった状況でなければ大丈夫だと思いました。
impl Solution {
pub fn intersection(nums1: Vec<i32>, nums2: Vec<i32>) -> Vec<i32> {
if nums1.len() > nums2.len() {
return Self::intersection(nums2, nums1);
}
let linear_search_base = &nums1;
let others: HashSet<i32> = HashSet::from_iter(nums2);
let mut intersected: HashSet<i32> = HashSet::with_capacity(nums1.len());
// ここで全走査するので、サイズが小さい方が効率が良い
for base in linear_search_base.into_iter() {
if others.contains(&base) {
intersected.insert(*base);
}
}
intersected.into_iter().collect()
}
}
問題: 349. Intersection of Two Arrays
次に解く問題: 929. Unique Email Addresses
ファイルの構成:
./src/bin/<各ステップ>.rs