Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions 238_ProductofArrayExceptSelf/main/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# コンパイラの設定
CXX = g++
# コンパイルオプション
CXXFLAGS = -std=c++17 -Wall -Wextra -O2 -I/Library/Developer/CommandLineTools/SDKs/MacOSX15.2.sdk/usr/include/c++/v1/

# 実行ファイル名
TARGET = main
SRC = main.cpp
HDR = main.h

# オブジェクトファイル(.o)の名前
OBJ = $(SRC:.cc=.o)

# デフォルトターゲット:実行ファイルを作成
all: $(TARGET)

# 実行ファイルを作成するルール
$(TARGET): $(OBJ)
# オブジェクトファイルから実行ファイルを作成
$(CXX) $(CXXFLAGS) -o $@ $^

# .cc から .o を作成するルール
%.o: %.cc $(HDR)
# ソースコードをコンパイルしてオブジェクトファイルを生成
$(CXX) $(CXXFLAGS) -c $< -o $@

# クリーンアップターゲット:コンパイル生成物を削除
clean:
# コンパイルで生成されたオブジェクトファイルと実行ファイルを削除
rm -f $(OBJ) $(TARGET)
Binary file added 238_ProductofArrayExceptSelf/main/main
Binary file not shown.
35 changes: 35 additions & 0 deletions 238_ProductofArrayExceptSelf/main/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "main.h"
#include <iostream>

// Solution::をつけないとグローバル関数となる
std::vector<int> Solution::productExceptSelf(std::vector<int>& nums) {
if (nums.size() == 0) {
Copy link

Choose a reason for hiding this comment

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

nums.empty() のほうがシンプルだと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

@nodchip
レビューありがとうございます。確かにこちらの方が素直ですね。step4_2に追加しました。またこちらのもので3回書ける練習をしました。

return {};
}
std::vector<int> products_except_self(nums.size(), 1);
int prefix_product = 1;
for (int i = 0; i < nums.size(); i++) {
products_except_self[i] *= prefix_product;
prefix_product *= nums[i];
}

int suffix_product = 1;
for (int i = nums.size() - 1; i >= 0; i--) {
products_except_self[i] *= suffix_product;
suffix_product *= nums[i];
}

return products_except_self;
}

int main() {
Solution solution;
std::vector<int> nums = {-1,1,0,-3,3};
std::vector<int> products = solution.productExceptSelf(nums);
std::cout << "Output is: ";
for (int product : products) {
std::cout << product << " ";
}
std::cout << std::endl;
return 0;
}
11 changes: 11 additions & 0 deletions 238_ProductofArrayExceptSelf/main/main.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef PRODUCT_EXCEPT_SELF_MAIN_MAIN_H_ // The format of the symbol name should be <PROJECT>_<PATH>_<FILE>_H_.
#define PRODUCT_EXCEPT_SELF_MAIN_MAIN_H_

#include <vector>

class Solution {
public:
std::vector<int> productExceptSelf(std::vector<int>& nums);
};

#endif
57 changes: 57 additions & 0 deletions 238_ProductofArrayExceptSelf/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## ステップ1
O(n)で実装する必要があるためvectorを2回見ていく方法は使えない
全てを掛け合わせた数字を出してから、nums[i]を割っていいく方法が思いついたが
割り算も制約上使えない

問題をもう一度読み直す
>The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.
わざわざprefixとsuffixが記載があるということをヒントに
iの位置までの合計とiより後ろの合計を管理するvectorを二つ用意して

最終的に掛け合わせると回答できそう
時間計算量O(n)
空間計算量O(n)

acceptまで30分

## ステップ2
nums[i]を掛ける順序とタイミングを考えれば、
iの位置までの合計とiより後ろの合計を管理するvectorを使う必要がなくなる。

prefix_productとsuffix_productを使ってそれぞれ左側と右側の積を保持する。
products_except_self[i]に掛けた後に、
prefix_productとsuffix_productをnums[i]で更新することで、
各ステップではnums[i]を除いた積だけが使われるようになっている
=>いきなりこの解法に辿り着くのは難しそう

vector<int>の初期化について
https://stackoverflow.com/questions/42743604/default-values-when-creating-a-vector-c
いつも忘れるので気になったら都度読む癖をつける
Copy link

Choose a reason for hiding this comment

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

2次元行列作るときに使っていますね。


Copy link

Choose a reason for hiding this comment

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

vector<int> productExceptSelf(vector<int>& nums) {
    int n = nums.size();
    vector<int> prefix(n, 1);
    partial_sum(nums.begin(), nums.end() - 1, prefix.begin() + 1, multiplies<int>());
    vector<int> suffix(n, 1);
    partial_sum(nums.rbegin(), nums.rend() - 1, suffix.rbegin() + 1, multiplies<int>());
    vector<int> result(n);
    transform(prefix.begin(), prefix.end(), suffix.begin(), result.begin(), multiplies<int>());
    return result;
}

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.

@oda
レビューありがとうございます。
普段使っているもの(主にvector、map、set)以外に関しても足を運んで調べる姿勢をよりつけないとと感じました。
まずはpartial_sum、multiplies、transformをきちんと理解しておいて今後のコーディングで活かせるようにしたいと思います。

## ステップ3
**3回書き直しやりましょう、といっているのは、不自然なところや負荷の高いところは覚えられないからです。**

## 他の方の解法
prefixやsuffixを単体で使うよりprefix_〇〇というように何が入っているのかわかるような名前がいいと感じた
resやlengthに関しても何が入っているのか分かるような変数名をつけたい
https://github.com/t-ooka/leetcode/pull/5

indexの管理方法を考えることで左側の積と右側の積を一度に計算することができる
Copy link

Choose a reason for hiding this comment

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

できますが、私はそんなに推奨しませんね。

https://discord.com/channels/1084280443945353267/1200089668901937312/1200403156073455646
## Discorなど

# PRに対するコメント
partial_sumとtransformを使っても解答可能
=>いずれの関数も知らなかったので普段使っている物以外にも足を伸ばす姿勢を意識。

partial_sum
https://cpprefjp.github.io/reference/numeric/partial_sum.html
https://en.cppreference.com/w/cpp/algorithm/partial_sum

multiplies
https://cpprefjp.github.io/reference/functional/multiplies.html
https://en.cppreference.com/w/cpp/utility/functional/multiplies

transform
https://cpprefjp.github.io/reference/algorithm/transform.html
https://en.cppreference.com/w/cpp/algorithm/transform
27 changes: 27 additions & 0 deletions 238_ProductofArrayExceptSelf/step1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
if (nums.size() == 0) {
return {};
}
vector<int> prefix_products(nums.size());
// デフォルトの初期化は0だが、
// indexが0の場所の計算に影響を与えないように1で初期化する
prefix_products[0] = 1;
for (int i = 1; i < nums.size(); i++) {
prefix_products[i] = prefix_products[i - 1] * nums[i - 1];
}

vector<int> suffix_products(nums.size());
suffix_products[nums.size() - 1] = 1;
for (int i = nums.size() - 2; i >= 0; i--) {
suffix_products[i] = suffix_products[i + 1] * nums[i + 1];
}

vector<int> products_except_self(nums.size());
for (int i = 0; i < nums.size(); i++) {
products_except_self[i] = prefix_products[i] * suffix_products[i];
}
return products_except_self;
}
};
24 changes: 24 additions & 0 deletions 238_ProductofArrayExceptSelf/step2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
if (nums.size() == 0) {
return {};
}

// デフォルトは0で初期化されるので1で初期化しておく
vector<int> products_except_self(nums.size(), 1);
int prefix_product = 1;
for (int i = 0; i < nums.size(); i++) {
products_except_self[i] *= prefix_product;
prefix_product *= nums[i];
}

int suffix_product = 1;
for (int i = nums.size() - 1; i >= 0; i--) {
products_except_self[i] *= suffix_product;
suffix_product *= nums[i];
}

return products_except_self;
}
};
23 changes: 23 additions & 0 deletions 238_ProductofArrayExceptSelf/step3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
if (nums.size() == 0) {
return {};
}

vector<int> products_except_self(nums.size(), 1);
int prefix_product = 1;
for (int i = 0; i < nums.size(); i++) {
products_except_self[i] *= prefix_product;
prefix_product *= nums[i];
}

int suffix_product = 1;
for (int i = nums.size() - 1; i >= 0; i--) {
products_except_self[i] *= suffix_product;
suffix_product *= nums[i];
}

return products_except_self;
}
};
21 changes: 21 additions & 0 deletions 238_ProductofArrayExceptSelf/step4_1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
if (nums.empty()) {
return {};
}

int num_size = nums.size();

vector<int> prefix_products(num_size, 1);
partial_sum(nums.begin(), nums.end() - 1, prefix_products.begin() + 1, multiplies<int>());

vector<int> suffix_products(num_size, 1);
partial_sum(nums.rbegin(), nums.rend() - 1, suffix_products.rbegin() + 1, multiplies<int>());

vector<int> products_except_self(num_size);
transform(prefix_products.begin(), prefix_products.end(), suffix_products.begin(),
products_except_self.begin(), multiplies<int>());
return products_except_self;
}
};
23 changes: 23 additions & 0 deletions 238_ProductofArrayExceptSelf/step4_2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
if (nums.empty()) {
return {};
}

vector<int> products_except_self(nums.size(), 1);
int prefix_product = 1;
for (int i = 0; i < nums.size(); i++) {
products_except_self[i] *= prefix_product;
prefix_product *= nums[i];
}

int suffix_product = 1;
for (int i = nums.size() - 1; i >= 0; i--) {
products_except_self[i] *= suffix_product;
suffix_product *= nums[i];
}

return products_except_self;
}
};