From 253e58217ba8b8f74bcfc2ce2876b178267e6f9c Mon Sep 17 00:00:00 2001 From: kazukiii Date: Sun, 9 Jun 2024 16:31:55 -0700 Subject: [PATCH 1/4] =?UTF-8?q?step1,=20step2,=20step3=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arai60/add-two-numbers/README.md | 29 ++++++++++++++++++++++++ arai60/add-two-numbers/step1.cpp | 39 ++++++++++++++++++++++++++++++++ arai60/add-two-numbers/step2.cpp | 35 ++++++++++++++++++++++++++++ arai60/add-two-numbers/step3.cpp | 35 ++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+) create mode 100644 arai60/add-two-numbers/README.md create mode 100644 arai60/add-two-numbers/step1.cpp create mode 100644 arai60/add-two-numbers/step2.cpp create mode 100644 arai60/add-two-numbers/step3.cpp diff --git a/arai60/add-two-numbers/README.md b/arai60/add-two-numbers/README.md new file mode 100644 index 0000000..6fa70f6 --- /dev/null +++ b/arai60/add-two-numbers/README.md @@ -0,0 +1,29 @@ +## 考察 +- 過去に解いたことあり +- 方針 + - 繰り上がりを保持しながら、対応するノードを一つずつ足していけばよさそう(頭の中では筆算を連想) + - time: O(n), space: O(n) + - 繰り上がりが最後に残った場合のみ注意 +- リストの走査は繰り返しでも再帰でもOK + - 再帰にするメリットは思いつかないので繰り返しでいく +- あとは実装 + +## Step1 +- 上で考えたアルゴリズムを実装 +- 1つ気になるのがメモリ管理のところ + - 新しいノードをスタック領域に確保するとスコープを抜けた時点でメモリが解放されるのでうまくいかない + - ヒープ領域にオブジェクトを作成したけど、このオブジェクトの管理は誰の責務になるのかがわかっていない + - C++実務で使ったことないが、実務だとどうやるんだろう + - Linked Listのポインタをスマートポインタにすればよさそう? -> 参照が切れた時点で自動的にメモリが解放されそう + +## Step2 +- メモリ管理について他の人のPRをいくつか検索してみた + - LeetCode上の制限という問題もありそう。ただ問題意識は常に持っていたい。 + - Ref. https://github.com/Ryotaro25/leetcode_first60/pull/5#discussion_r1611301775 +- 最後にcarryをチェックして、1を追加していたところをメインロジックに吸収できたので修正した + +## Step3 +- 1回目: 2m00s +- 2回目: 1m58s +- 3回目: 1m33s + diff --git a/arai60/add-two-numbers/step1.cpp b/arai60/add-two-numbers/step1.cpp new file mode 100644 index 0000000..68a4179 --- /dev/null +++ b/arai60/add-two-numbers/step1.cpp @@ -0,0 +1,39 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* addTwoNumbers(ListNode* list1, ListNode* list2) { + int carry = 0; + ListNode dummy_head; + ListNode* node = &dummy_head; + while (list2 || list1) { + int sum = carry; + if (list1) { + sum += list1->val; + list1 = list1->next; + } + if (list2) { + sum += list2->val; + list2 = list2->next; + } + + carry = sum / 10; + node->next = new ListNode(sum % 10); + node = node->next; + } + + if (carry == 1) { + node->next = new ListNode(1); + } + + return dummy_head.next; + } +}; diff --git a/arai60/add-two-numbers/step2.cpp b/arai60/add-two-numbers/step2.cpp new file mode 100644 index 0000000..29a4841 --- /dev/null +++ b/arai60/add-two-numbers/step2.cpp @@ -0,0 +1,35 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* addTwoNumbers(ListNode* list1, ListNode* list2) { + int carry = 0; + ListNode dummy_head; + ListNode* node = &dummy_head; + while (list1 || list2 || carry) { + int sum = carry; + if (list1) { + sum += list1->val; + list1 = list1->next; + } + if (list2) { + sum += list2->val; + list2 = list2->next; + } + + carry = sum / 10; + node->next = new ListNode(sum % 10); + node = node->next; + } + + return dummy_head.next; + } +}; diff --git a/arai60/add-two-numbers/step3.cpp b/arai60/add-two-numbers/step3.cpp new file mode 100644 index 0000000..06c3d30 --- /dev/null +++ b/arai60/add-two-numbers/step3.cpp @@ -0,0 +1,35 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* addTwoNumbers(ListNode* list1, ListNode* list2) { + ListNode dummy_head; + ListNode* node = &dummy_head; + int carry = 0; + while (list1 || list2 || carry) { + int sum = carry; + if (list1) { + sum += list1->val; + list1 = list1->next; + } + if (list2) { + sum += list2->val; + list2 = list2->next; + } + + carry = sum / 10; + node->next = new ListNode(sum % 10); + node = node->next; + } + + return dummy_head.next; + } +}; From c9ba9b4e34c8cd3b396b092525d1805f61d7c0bf Mon Sep 17 00:00:00 2001 From: kazukiii Date: Mon, 10 Jun 2024 14:58:54 -0700 Subject: [PATCH 2/4] =?UTF-8?q?=E5=86=8D=E5=B8=B0=E7=89=88=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arai60/add-two-numbers/step1_recursion.cpp | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 arai60/add-two-numbers/step1_recursion.cpp diff --git a/arai60/add-two-numbers/step1_recursion.cpp b/arai60/add-two-numbers/step1_recursion.cpp new file mode 100644 index 0000000..9ceff6c --- /dev/null +++ b/arai60/add-two-numbers/step1_recursion.cpp @@ -0,0 +1,43 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* addTwoNumbers(ListNode* list1, ListNode* list2) { + ListNode dummy_head; + ListNode* node = &dummy_head; + int carry = 0; + + add(list1, list2, carry, node); + + return dummy_head.next; + } + +private: + void add(ListNode* list1, ListNode* list2, int carry, ListNode* node) { + if (!list1 && !list2 && !carry) return; + + int sum = carry; + if (list1) { + sum += list1->val; + list1 = list1->next; + } + if (list2) { + sum += list2->val; + list2 = list2->next; + } + + carry = sum / 10; + node->next = new ListNode(sum % 10); + node = node->next; + + add(list1, list2, carry, node); + } +}; From a9c7637c616aef971424c999f24d49573541daec Mon Sep 17 00:00:00 2001 From: kazukiii Date: Mon, 10 Jun 2024 15:13:30 -0700 Subject: [PATCH 3/4] =?UTF-8?q?dummy=E3=82=92=E4=BD=BF=E3=82=8F=E3=81=AA?= =?UTF-8?q?=E3=81=84=E7=89=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../add-two-numbers/step3_without_dummy.cpp | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 arai60/add-two-numbers/step3_without_dummy.cpp diff --git a/arai60/add-two-numbers/step3_without_dummy.cpp b/arai60/add-two-numbers/step3_without_dummy.cpp new file mode 100644 index 0000000..15380ee --- /dev/null +++ b/arai60/add-two-numbers/step3_without_dummy.cpp @@ -0,0 +1,40 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* addTwoNumbers(ListNode* list1, ListNode* list2) { + ListNode* head = nullptr; + ListNode* node = nullptr; + int carry = 0; + while (list1 || list2 || carry) { + int sum = carry; + if (list1) { + sum += list1->val; + list1 = list1->next; + } + if (list2) { + sum += list2->val; + list2 = list2->next; + } + + carry = sum / 10; + if (!head) { + head = new ListNode(sum % 10); + node = head; + continue; + } + node->next = new ListNode(sum % 10); + node = node->next; + } + + return head; + } +}; From 8d20112f18c4fb7bfcc96731aa1af727cec75a2e Mon Sep 17 00:00:00 2001 From: kazukiii Date: Mon, 1 Jul 2024 00:17:31 -0700 Subject: [PATCH 4/4] =?UTF-8?q?README-en=E3=82=92=E8=BF=BD=E5=8A=A0(?= =?UTF-8?q?=E8=AA=AC=E6=98=8E=E7=B7=B4=E7=BF=92=E7=94=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arai60/add-two-numbers/README-en.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 arai60/add-two-numbers/README-en.md diff --git a/arai60/add-two-numbers/README-en.md b/arai60/add-two-numbers/README-en.md new file mode 100644 index 0000000..ef43566 --- /dev/null +++ b/arai60/add-two-numbers/README-en.md @@ -0,0 +1,28 @@ +## Considerations +- Solved this problem in the past +- Approach + - Keep track of carry while adding corresponding nodes one by one (similar to manual addition in your head) + - time: O(n), space: O(n) + - Pay special attention if a carry remains at the end +- Traversing the list can be done iteratively or recursively + - Can't think of any benefits for recursion, so will go with iteration +- Now to implement + +## Step 1 +- Implemented the algorithm considered above +- One concern is memory management + - Allocating new nodes on the stack won't work as memory is released when out of scope + - Created objects in the heap, but unsure who is responsible for managing these objects + - Haven't used C++ in a professional setting, but how is this handled in practice? + - Would using smart pointers for Linked List pointers help? -> Memory should be automatically released when references are gone + +## Step 2 +- Searched other people's PRs regarding memory management + - There might be limitations specific to LeetCode, but it's important to be aware of this issue + - Ref. https://github.com/Ryotaro25/leetcode_first60/pull/5#discussion_r1611301775 +- Fixed by incorporating the final carry check into the main logic + +## Step 3 +- First time: 2m00s +- Second time: 1m58s +- Third time: 1m33s