Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1588. Sum of All Odd Length Subarrays #89

Closed
twy30 opened this issue Nov 4, 2020 · 2 comments · Fixed by #90
Closed

1588. Sum of All Odd Length Subarrays #89

twy30 opened this issue Nov 4, 2020 · 2 comments · Fixed by #90
Labels

Comments

@twy30
Copy link
Contributor

twy30 commented Nov 4, 2020

https://leetcode.com/problems/sum-of-all-odd-length-subarrays/

using System.Linq;

public class Solution
{
    public int SumOddLengthSubarrays(int[] arr)
    {
        // 「輸入的數字」(複數)
        var inputNumbers = arr;

        // This is how we will solve this in O(n) time.
        //
        // Say we have inputNumbers like this:
        //
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        //
        // ---
        //
        // These are all of the 1-length subarrays:
        //
        // {n₁}
        //     {n₂}
        //         {n₃}
        //             {n₄}
        //                 {n₅}
        //                     {n₆}
        //                          ...
        //                               {n₋₆}
        //                                    {n₋₅}
        //                                         {n₋₄}
        //                                              {n₋₃}
        //                                                   {n₋₂}
        //                                                        {n₋₁}
        //
        // They add up like this:
        //
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        //
        // ---
        //
        // These are all of the 3-length subarrays:
        //
        // {n₁, n₂, n₃}
        //     {n₂, n₃, n₄}
        //         {n₃, n₄, n₅}
        //             {n₄, n₅, n₆}
        //                 {n₅, n₆, ...
        //                     {n₆, ...
        //                          ...
        //                          ... , n₋₆}
        //                          ... , n₋₆, n₋₅}
        //                               {n₋₆, n₋₅, n₋₄}
        //                                    {n₋₅, n₋₄, n₋₃}
        //                                         {n₋₄, n₋₃, n₋₂}
        //                                              {n₋₃, n₋₂, n₋₁}
        //
        // They add up like this:
        //
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {    n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂,    }
        // {        n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃,         }
        //
        // It is equivlent to:
        //
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // -n₁                                                    -n₋₁
        // -n₁ -n₂                                           -n₋₂ -n₋₁
        //
        // ---
        //
        // We can list all 5-length subarrays and add them up.  It will
        // turn out like this:
        //
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // -n₁                                                    -n₋₁
        // -n₁ -n₂                                           -n₋₂ -n₋₁
        // -n₁ -n₂ -n₃                                  -n₋₃ -n₋₂ -n₋₁
        // -n₁ -n₂ -n₃ -n₄                         -n₋₄ -n₋₃ -n₋₂ -n₋₁
        //
        // ---
        //
        // This is the case for 7-length subarrays.
        //
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // {n₁, n₂, n₃, n₄, n₅, n₆, ... , n₋₆, n₋₅, n₋₄, n₋₃, n₋₂, n₋₁}
        // -n₁                                                    -n₋₁
        // -n₁ -n₂                                           -n₋₂ -n₋₁
        // -n₁ -n₂ -n₃                                  -n₋₃ -n₋₂ -n₋₁
        // -n₁ -n₂ -n₃ -n₄                         -n₋₄ -n₋₃ -n₋₂ -n₋₁
        // -n₁ -n₂ -n₃ -n₄ -n₅                -n₋₅ -n₋₄ -n₋₃ -n₋₂ -n₋₁
        // -n₁ -n₂ -n₃ -n₄ -n₅ -n₆       -n₋₆ -n₋₅ -n₋₄ -n₋₃ -n₋₂ -n₋₁
        //
        // ---
        //
        // This pattern will continue to hold for all (2m+1)-length
        // subarrays, and we will take advantage of it.

        // 「最大的 Subarray 長度」
        var maxSubarrayLength = inputNumbers.Length % 2 == 0 ? inputNumbers.Length - 1 : inputNumbers.Length;

        // 「最小的 Subarray 長度」
        const int minSubarrayLength = 1;

        // 「Subarray 長度的公差」
        const int subarrayLengthCommonDifference = 2;

        // 「輸出值」
        var output = inputNumbers.Sum() * (maxSubarrayLength + minSubarrayLength) * ((maxSubarrayLength - minSubarrayLength) / subarrayLengthCommonDifference + 1) / 2;

        // 「『多餘的項數』的數量變數1」
        var excessiveTermCount1 = 1;

        // 「『多餘的項數』的數量變數2」
        var excessiveTermCount2 = 2;

        // 「『多餘的項數』的數量的差1」
        var excessiveTermCountDifference1 = 1;

        // 「『多餘的項數』的數量的差2」
        var excessiveTermCountDifference2 = 2;

        for (int i = maxSubarrayLength - 2; i > 0; i -= 2)
        {
            output -= inputNumbers[i - 1] * excessiveTermCount2;
            output -= inputNumbers[i] * excessiveTermCount1;
            output -= inputNumbers[inputNumbers.Length - i - 1] * excessiveTermCount1;
            output -= inputNumbers[inputNumbers.Length - i] * excessiveTermCount2;

            excessiveTermCountDifference1 += 2;
            excessiveTermCountDifference2 += 2;
            excessiveTermCount1 += excessiveTermCountDifference1;
            excessiveTermCount2 += excessiveTermCountDifference2;
        }

        return output;
    }
}

參考資料

等差數列

https://en.wikipedia.org/wiki/Arithmetic_progression

  • 項數: term
  • 差: difference

請參考「刷 LeetCode 練習命名」 #69 😊

@twy30 twy30 added the LeetCode label Nov 4, 2020
@twy30
Copy link
Contributor Author

twy30 commented Nov 4, 2020

這個案例很有趣 🤔

與其它處理「實物」的情景相比,這裡處理的是抽象的數學觀念。

我覺得「命名」在這裡對程式碼讀者的幫助有限,還是要用註解來解釋這個 O(n) 解的演算法的推導過程。

@twy30
Copy link
Contributor Author

twy30 commented Nov 6, 2020

修改了 LeetCode 答案,補上對解題演算法的註解。

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

Successfully merging a pull request may close this issue.

1 participant