Skip to content

Latest commit

 

History

History
999 lines (798 loc) · 38.1 KB

File metadata and controls

999 lines (798 loc) · 38.1 KB

ToC

August Week 1

24.07.29 - 1395. Count Number of Teams

문제 링크

// 2783ms, 11.52MB
class Solution {
public:
    int numTeams(vector<int>& rating) {
        const int SIZE = static_cast<int>(rating.size());
        int answer{};
        
        for (int i{}; i < SIZE - 2; ++i) {
            for (int j = i + 1; j < SIZE - 1; ++j) {
                for (int k = j + 1; k < SIZE; ++k) {
                    if ((rating[i] < rating[j] && rating[j] < rating[k]) ||
                        (rating[i] > rating[j] && rating[j] > rating[k])) {
                        ++answer;
                    }
                }
            }
        }
        
        return answer;
    }
};

gpt

Since I couldn't access the page directly, I'll provide an outline on how to solve the "Count Number of Teams" problem typically found on LeetCode.

Brute Force

Problem Description

You are given an array of integers representing the rating of soldiers. You need to count the number of teams of 3 soldiers where either:

  • The ratings are in increasing order (i < j < k).
  • The ratings are in decreasing order (i > j > k).

Solution

We can solve this problem using a nested loop approach to count valid teams. Here's a step-by-step solution in C++:

  1. Initialization: We need an array rating and its length n.
  2. Nested Loops: Use three nested loops to check each combination of three soldiers.
  3. Condition Checking: Check for increasing or decreasing order.
  4. Counting Teams: Increment a counter whenever a valid team is found.

Example Code

Here’s a C++ solution for the problem:
class Solution {
public:
    int numTeams(vector<int>& rating) {
        int n = rating.size();
        int count = 0;
        
        // Iterate over all possible triplets (i, j, k)
        for (int i = 0; i < n - 2; ++i) {
            for (int j = i + 1; j < n - 1; ++j) {
                for (int k = j + 1; k < n; ++k) {
                    if ((rating[i] < rating[j] && rating[j] < rating[k]) ||
                        (rating[i] > rating[j] && rating[j] > rating[k])) {
                        ++count;
                    }
                }
            }
        }
        
        return count;
    }
};

Explanation

  1. Triple Loop: The loops run through all combinations of indices (i, j, k) with i < j < k.
  2. Condition Check: The condition checks if the ratings are in either strictly increasing or decreasing order.
  3. Count Increment: The counter count is incremented whenever a valid team is found.

Optimizations

This triple loop approach works fine for small arrays but may not be efficient for larger ones due to O(n^3) complexity. For larger arrays, consider more efficient solutions involving dynamic programming or prefix/suffix arrays to reduce time complexity.

Dynamic Programming

To solve the "Count Number of Teams" problem using a more efficient approach with dynamic programming, we can use the following strategy:

  1. Count of Smaller and Larger Elements: For each soldier, count the number of soldiers with a lower rating before it and the number of soldiers with a higher rating after it. Similarly, count the number of soldiers with a higher rating before it and the number of soldiers with a lower rating after it.
  2. Count Valid Teams: Using these counts, we can determine the number of valid increasing and decreasing teams.

Example Code

Here is a more efficient C++ solution:
class Solution {
public:
    int numTeams(vector<int>& rating) {
        int n = rating.size();
        int result = 0;
        
        for (int j = 0; j < n; ++j) {
            int less_left = 0, greater_left = 0;
            int less_right = 0, greater_right = 0;
            
            // Count elements smaller/greater than rating[j] to the left of j
            for (int i = 0; i < j; ++i) {
                if (rating[i] < rating[j]) {
                    ++less_left;
                } else if (rating[i] > rating[j]) {
                    ++greater_left;
                }
            }
            
            // Count elements smaller/greater than rating[j] to the right of j
            for (int k = j + 1; k < n; ++k) {
                if (rating[k] < rating[j]) {
                    ++less_right;
                } else if (rating[k] > rating[j]) {
                    ++greater_right;
                }
            }
            
            // Calculate the number of valid teams with j as the middle soldier
            result += less_left * greater_right + greater_left * less_right;
        }
        
        return result;
    }
};

Explanation

  1. Initialization: Initialize counters for elements smaller and greater than the current element both to the left and right.
  2. Loop Through Array: For each element in the array, count elements smaller and greater to its left and right.
  3. Count Valid Teams: The number of valid teams with the current element as the middle soldier is the sum of products of valid left and right combinations.

Complexity

This approach reduces the time complexity to O(n^2), which is more efficient than the O(n^3) solution but still manageable for moderately sized arrays. For very large arrays, further optimizations may be necessary.

prefix/suffix arrays

To solve the "Count Number of Teams" problem using prefix/suffix arrays, we can optimize the counting of elements that are smaller or larger than the current element. Here's how:

  1. Prefix Arrays: Use prefix arrays to count the number of elements smaller or larger than the current element up to that index.
  2. Suffix Arrays: Use suffix arrays to count the number of elements smaller or larger than the current element from that index to the end.
  3. Counting Valid Teams: Use these counts to determine the number of valid teams.

Example Code

Here's a C++ solution using prefix and suffix arrays:

class Solution {
public:
    int numTeams(vector<int>& rating) {
        int n = rating.size();
        vector<int> lessLeft(n, 0), greaterLeft(n, 0);
        vector<int> lessRight(n, 0), greaterRight(n, 0);
        
        // Fill the prefix arrays
        for (int i = 1; i < n; ++i) {
            for (int j = 0; j < i; ++j) {
                if (rating[j] < rating[i]) {
                    ++lessLeft[i];
                } else if (rating[j] > rating[i]) {
                    ++greaterLeft[i];
                }
            }
        }
        
        // Fill the suffix arrays
        for (int i = n - 2; i >= 0; --i) {
            for (int j = n - 1; j > i; --j) {
                if (rating[j] < rating[i]) {
                    ++lessRight[i];
                } else if (rating[j] > rating[i]) {
                    ++greaterRight[i];
                }
            }
        }
        
        int count = 0;
        
        // Count the number of valid teams
        for (int i = 0; i < n; ++i) {
            count += lessLeft[i] * greaterRight[i] + greaterLeft[i] * lessRight[i];
        }
        
        return count;
    }
};

Explanation

  1. Prefix Arrays: lessLeft[i] and greaterLeft[i] store the count of elements smaller and greater than rating[i] to the left of i.
  2. Suffix Arrays: lessRight[i] and greaterRight[i] store the count of elements smaller and greater than rating[i] to the right of i.
  3. Counting Teams: For each index i, the number of valid teams is calculated using the counts from prefix and suffix arrays:
    • lessLeft[i] * greaterRight[i] gives the count of teams where rating[i] is the middle element in an increasing sequence.
    • greaterLeft[i] * lessRight[i] gives the count of teams where rating[i] is the middle element in a decreasing sequence.

This approach is more efficient than the brute-force solution, reducing the overall complexity to O(n^2). For further improvements, more advanced data structures like Fenwick Trees or Segment Trees could be used to reduce the complexity to O(n log n).

24.07.30 - 1653. Minimum Deletions to Make String Balanced

문제 링크

// 82ms, 23.68MB
class Solution {
public:
    int minimumDeletions(string s) {
        int totA{};
        for(auto c : s) {
            if(c == 'a') ++totA;
        }

        int answer = totA;
        int cntA{}, cntB{};
        for(auto c : s) {
            if(c == 'a') ++cntA;
            else if(c == 'b') ++cntB;

            answer = min(answer, cntB + totA - cntA);
        }
        return answer;
    }
};

gpt

To solve the problem of finding the minimum number of deletions required to make a string balanced, we need to ensure that all 'a's in the string appear before all 'b's. This problem can be approached using dynamic programming or a more optimized two-pass strategy with prefix sums.

Here’s the detailed approach:

Two-Pass Approach with Prefix Sums

  1. Prefix Calculation:

    • Calculate the number of 'b's to the left of each position (prefix_b).
    • Calculate the number of 'a's to the right of each position (suffix_a).
  2. Compute Minimum Deletions:

    • For each position, compute the total deletions needed to make the string balanced if the split occurs at that position.
    • Track the minimum deletions across all possible split positions.

Here’s the implementation:

// 87ms, 53.17MB
class Solution {
public:
    int minimumDeletions(string s) {
        int n = s.size();
        std::vector<int> prefix_b(n + 1, 0); // number of 'b's to the left of i (exclusive)
        std::vector<int> suffix_a(n + 1, 0); // number of 'a's to the right of i (exclusive)
        
        // Fill prefix_b array
        for (int i = 1; i <= n; ++i) {
            prefix_b[i] = prefix_b[i - 1] + (s[i - 1] == 'b' ? 1 : 0);
        }
        
        // Fill suffix_a array
        for (int i = n - 1; i >= 0; --i) {
            suffix_a[i] = suffix_a[i + 1] + (s[i] == 'a' ? 1 : 0);
        }
        
        // Compute minimum deletions
        int min_deletions = n; // Initialize with maximum possible deletions (all characters)
        for (int i = 0; i <= n; ++i) {
            min_deletions = std::min(min_deletions, prefix_b[i] + suffix_a[i]);
        }
        
        return min_deletions;
    }
};

Explanation:

  1. Prefix Array Calculation:

    • prefix_b[i] counts the number of 'b's in the substring s[0...i-1].
    • Iterate through the string and populate prefix_b.
  2. Suffix Array Calculation:

    • suffix_a[i] counts the number of 'a's in the substring s[i...n-1].
    • Iterate through the string in reverse and populate suffix_a.
  3. Finding the Minimum Deletions:

    • For each possible split point i, compute the sum of prefix_b[i] (deletions needed for 'b's before i) and suffix_a[i] (deletions needed for 'a's after i).
    • Track the minimum of these sums.

Complexity:

  • Time Complexity: O(n), where n is the length of the string. This is because we iterate through the string a constant number of times.
  • Space Complexity: O(n) for the prefix and suffix arrays.

This approach ensures that the solution is efficient and optimal for the given problem constraints.

24.07.31 - 1105. Filling Bookcase Shelves

문제 해결

해결 못 했습니다.. ㅠㅠ (아이디어가 안 떠 오름.)

gpt

To solve the problem of "Filling Bookcase Shelves" from LeetCode, you need to approach it using dynamic programming (DP). The problem can be summarized as arranging a set of books on shelves such that the total height of the shelves is minimized. Each book has a width and a height, and each shelf has a maximum width limit.

Here's a step-by-step solution:

  1. Understand the Problem:

    • You have an array of books, where each book is represented by its width and height.
    • You need to arrange these books on shelves with a given maximum width.
    • The goal is to minimize the total height of the shelves.
  2. Define the DP State:

    • Let dp[i] represent the minimum height needed to place the first i books.
  3. DP Transition:

    • For each book i, you decide whether to place it on a new shelf or add it to the current shelf if it fits within the width constraint.
    • You update the dp array by considering the height of the current shelf and the books that fit on it.
  4. Base Case:

    • dp[0] = 0, which means no height is needed for zero books.

Here is the complete code for solving the problem using dynamic programming:

// 3ms, 11.11MB
class Solution {
public:
    int minHeightShelves(vector<vector<int>>& books, int shelf_width) {
        int n = books.size();
        vector<int> dp(n + 1, INT_MAX);
        dp[0] = 0;

        for (int i = 1; i <= n; ++i) {
            int width = 0, height = 0;
            for (int j = i; j > 0; --j) {
                width += books[j-1][0];
                if (width > shelf_width) break;
                height = max(height, books[j-1][1]);
                dp[i] = min(dp[i], dp[j-1] + height);
            }
        }

        return dp[n];
    }
};

Explanation of the Code:

  • Initialization:
    • dp vector is initialized to INT_MAX except dp[0] which is 0 because no height is needed for zero books.
  • Outer Loop:
    • Iterate over each book i from 1 to n.
  • Inner Loop:
    • Check the books from the current book i backwards to see how many can fit on the current shelf without exceeding the shelf_width.
    • Update the width and height of the current shelf.
    • Update dp[i] to the minimum value between its current value and the height of the shelf plus the height from the previous books (dp[j-1] + height).
  • Return the Result:
    • The final result will be in dp[n], which represents the minimum height to arrange all n books.

Tips:

  • Ensure you understand the dynamic programming state transition.
  • Carefully handle the conditions within the inner loop to avoid exceeding the shelf width.
  • The solution leverages the fact that placing a book on a new shelf vs. the current shelf is mutually exclusive and must be evaluated at each step.

Note

예제에서 첫 책을 쌓고, 두 번째 세 번째 책을 쌓을 때 점화식을 생각 못 했다.

두 번째 책까지만 쌓으면 최소 높이는 3이고 min 값을 거기서 갱신해버리면 이후 답이 제대로 나오지 않는다. 이럴 때는 거꾸로 볼 수 있다는 아이디어가 있다는 것을 깨달았다. (무조건 정방향으로 볼 필요는 없다.)

24.08.01 - 2678. Number of Senior Citizens

문제 링크

// 10ms, 17.6MB
class Solution {
public:
    int countSeniors(vector<string>& details) {
        // 10 characters => phone number
        // gender(M, F)
        // 2 characters => age
        // 2 characters => seat

        // # of passengers who are strictly more than 60 years old.

        int answer{};
        for(string& detail : details) {
            if(stoi(detail.substr(11, 2)) > 60) ++answer;
        }
        return answer;
    }
};

gpt

Certainly! The problem on LeetCode you are referring to is about counting the number of senior citizens in a given list of personal details. Here's a step-by-step solution in C++ to solve this problem.

The problem description states:

You are given a 0-indexed array of strings details. Each element of details is a string, where:

  • The first 2 characters represent the country code.
  • The next 8 characters represent the phone number.
  • The next 2 characters represent the age.
  • The last 1 character represents the gender.

Return the number of strings in details that represent senior citizens.

Here's how we can approach solving this problem in C++:

  1. Parse each string to extract the age.
  2. Convert the extracted age to an integer.
  3. Check if the age is greater than or equal to 60.
  4. Count how many such strings exist in the array.

Here's the C++ code to implement this logic:

class Solution {
public:
    int countSeniors(std::vector<std::string>& details) {
        int count = 0;
        for (const std::string& detail : details) {
            // The age is located at indices 10 and 11 in the string
            int age = std::stoi(detail.substr(10, 2));
            if (age >= 60) {
                count++;
            }
        }
        return count;
    }
};

Explanation:

  1. Loop through each string in the details vector: We use a range-based for loop to iterate through each string.
  2. Extract the age: detail.substr(10, 2) extracts the substring starting at index 10 with a length of 2, which corresponds to the age in the given format.
  3. Convert the substring to an integer: std::stoi converts the extracted substring to an integer.
  4. Check if the age is 60 or more: If the age is greater than or equal to 60, increment the count.
  5. Return the count: After checking all strings, return the final count of senior citizens.

This code correctly solves the problem as described. You can test it with various inputs to ensure it works for all edge cases as well.

I think age starts with index 11, isn't it?

You're right! The age starts at index 11. Here is the corrected code with the proper index for extracting the age:

class Solution {
public:
    int countSeniors(std::vector<std::string>& details) {
        int count = 0;
        for (const std::string& detail : details) {
            // The age is located at indices 11 and 12 in the string
            int age = std::stoi(detail.substr(11, 2));
            if (age >= 60) {
                count++;
            }
        }
        return count;
    }
};

Explanation:

  1. Loop through each string in the details vector: We use a range-based for loop to iterate through each string.
  2. Extract the age: detail.substr(11, 2) extracts the substring starting at index 11 with a length of 2, which corresponds to the age in the given format.
  3. Convert the substring to an integer: std::stoi converts the extracted substring to an integer.
  4. Check if the age is 60 or more: If the age is greater than or equal to 60, increment the count.
  5. Return the count: After checking all strings, return the final count of senior citizens.

This corrected code ensures that we are extracting the age from the correct indices in the string.

strictly more than 60 years old.

it doesn't contains 60..!

Thank you for the clarification. If the requirement is to count only those who are strictly more than 60 years old (i.e., age > 60), we need to adjust the condition in our check. Here is the corrected code:

// 13ms, 17.56MB
class Solution {
public:
    int countSeniors(const std::vector<std::string>& details) {
        int count = 0;
        for (const std::string& detail : details) {
            // The age is located at indices 11 and 12 in the string
            int age = std::stoi(detail.substr(11, 2));
            if (age > 60) {
                count++;
            }
        }
        return count;
    }
};

Explanation:

  • Extract the age: The age is extracted using detail.substr(11, 2) which gets the substring starting at index 11 with a length of 2 characters.
  • Convert the substring to an integer: The extracted age substring is converted to an integer using std::stoi.
  • Check if the age is strictly more than 60: The condition if (age > 60) is used to count only those ages that are strictly greater than 60.
  • Return the count: After iterating through all strings, the final count of senior citizens is returned.

This code correctly solves the problem with the updated condition that only counts those who are strictly older than 60.

약간의 오류 $\rightarrow$ 수정..

중간에 11번째가 아니라 13번째 아니야? 라고 물었는데 속지 않음.

24.08.02 - 2134. Minimum Swaps to Group All 1's Together II

문제 링크

아이디어가 떠오르지 않아 힌트 참고 했음..

  • Notice that the number of 1’s to be grouped together is fixed. It is the number of 1's the whole array has.
  • Call this number total. We should then check for every subarray of size total (possibly wrapped around), how many swaps are required to have the subarray be all 1’s.
  • The number of swaps required is the number of 0’s in the subarray.
  • To eliminate the circular property of the array, we can append the original array to itself. Then, we check each subarray of length total.
  • How do we avoid recounting the number of 0’s in the subarray each time? The Sliding Window technique can help.
// 71ms, 83.06MB
class Solution {
public:
    int minSwaps(std::vector<int>& nums) {
        const int SIZE = static_cast<int>(nums.size());
        
        // 총 1의 개수 카운팅
        int oneTot{};
        for(int& num : nums) {
            if(num == 1) ++oneTot;
        }
        
        int oneCntInWindow{}, maxOneCntInWindow{};

        // 초기 window 구성
        for (int i = 0; i < oneTot; ++i) {
            if (nums[i] == 1) {
                oneCntInWindow++;
            }
        }
        maxOneCntInWindow = oneCntInWindow;
        
        for (int i = oneTot; i < SIZE + oneTot; ++i) {
            if (nums[i % SIZE] == 1) {
               oneCntInWindow++;
            }
            if (nums[(i - oneTot) % SIZE] == 1) {
                oneCntInWindow--;
            }
            maxOneCntInWindow = std::max(maxOneCntInWindow, oneCntInWindow);
        }
        
        return oneTot - maxOneCntInWindow;
    }
};

gpt

Certainly! Let's solve the problem of finding the minimum number of swaps to group all 1s together in a circular array, as described in the LeetCode problem Minimum Swaps to Group All 1s Together II.

Problem Summary

Given a circular binary array, you need to find the minimum number of swaps required to group all the 1s together. The array can be rotated, making the circular nature a crucial aspect of the problem.

Approach

  1. Count the total number of 1s (totalOnes) in the array: This helps determine the window size that we need to use to group the 1s together.
  2. Create a double-length version of the array: This accounts for the circular nature by allowing the window to wrap around seamlessly.
  3. Use a sliding window technique: Count the number of 1s in the current window of size totalOnes. The goal is to maximize the number of 1s in any such window.
  4. Calculate the minimum swaps: The minimum number of swaps needed to bring all 1s together in the best window is determined by the difference between totalOnes and the maximum number of 1s found in any window.

Here's the detailed implementation:

// 76ms, 93.54MB
class Solution {
public:
    int minSwaps(std::vector<int>& nums) {
        int n = nums.size();
        
        // Count total number of 1s in the array
        int totalOnes = std::count(nums.begin(), nums.end(), 1);
        
        // Create a double-length array to handle circular nature
        std::vector<int> doubleNums(nums.begin(), nums.end());
        doubleNums.insert(doubleNums.end(), nums.begin(), nums.end());
        
        // Use sliding window to find maximum number of 1s in any window of size `totalOnes`
        int maxOnesInWindow = 0;
        int currentOnesInWindow = 0;
        
        for (int i = 0; i < totalOnes; ++i) {
            if (doubleNums[i] == 1) {
                currentOnesInWindow++;
            }
        }
        
        maxOnesInWindow = currentOnesInWindow;
        
        for (int i = totalOnes; i < doubleNums.size(); ++i) {
            if (doubleNums[i] == 1) {
                currentOnesInWindow++;
            }
            if (doubleNums[i - totalOnes] == 1) {
                currentOnesInWindow--;
            }
            maxOnesInWindow = std::max(maxOnesInWindow, currentOnesInWindow);
        }
        
        // The minimum number of swaps needed
        return totalOnes - maxOnesInWindow;
    }
};

Explanation

  1. Counting 1s: We first count the total number of 1s in the array (totalOnes). This will be the size of the window we need to consider for grouping the 1s together.
  2. Handling Circular Nature: By duplicating the array (doubleNums), we can handle the circular nature. This way, sliding windows can naturally wrap around the end of the array.
  3. Sliding Window Technique:
    • Initialize a window of size totalOnes and count the number of 1s in this window.
    • Slide the window one position at a time, updating the count of 1s by adding the new element and removing the old element that is no longer in the window.
    • Track the maximum number of 1s found in any window of size totalOnes.
  4. Calculating Minimum Swaps: The minimum number of swaps required is totalOnes - maxOnesInWindow.

This solution ensures an efficient and effective way to determine the minimum swaps needed, with a time complexity of $O(n)$ due to the linear traversal of the array.

24.08.03 - 1460. Make Two Arrays Equal by Reversing Subarrays

문제 링크

// 6ms, 17.8MB
class Solution {
public:
    bool canBeEqual(vector<int>& target, vector<int>& arr) {
        // 1 <= target[i], arr[i] <= 1000
        vector dat(1001, 0);
        for(int& t : target) dat[t]++;
        for(int& a : arr) {
            if(dat[a] > 0) {
                dat[a]--;
            }
            else {
                return false;
            }
        }
        return true;
    }
};

gpt

Sure! Let's go through the problem "Make Two Arrays Equal by Reversing Subarrays" on LeetCode.

Problem Description

You are given two integer arrays of equal length target and arr. In one step, you can select any non-empty subarray of arr and reverse it. You need to determine if it's possible to make arr equal to target by performing any number of such reversals.

Solution Approach

To determine if we can make arr equal to target by reversing subarrays, let's consider the following:

  1. Permutation Check: Any subarray reversal does not change the elements of the array but only their order. Therefore, for arr to be transformed into target, both arrays must contain the same elements with the same frequencies. In other words, arr must be a permutation of target.

If arr is a permutation of target, then it's always possible to sort arr to match target using a series of reversals. This is because any sequence of reversals can rearrange the elements to match any permutation.

Implementation

We can solve this problem efficiently by using sorting or a hashmap to check if arr is a permutation of target.

Here is a Python implementation using sorting:

// 4ms, 17.58MB
class Solution {
public:
    bool canBeEqual(vector<int>& target, vector<int>& arr) {
        sort(target.begin(), target.end());
        sort(arr.begin(), arr.end());
        return target == arr;
    }
};

이게 되네?..

Alternatively, here is the implementation using hash maps to count the frequency of each element:

// 10ms, 19.52MB
class Solution {
public:
    bool canBeEqual(vector<int>& target, vector<int>& arr) {
        unordered_map<int, int> countMap;
        for (int num : target) {
            countMap[num]++;
        }
        for (int num : arr) {
            if (countMap.find(num) == countMap.end() || countMap[num] == 0) {
                return false;
            }
            countMap[num]--;
        }
        return true;
    }
};

Explanation

  • Sorting Method: We sort both target and arr arrays. If they are identical after sorting, then arr can be transformed into target.
  • Hashmap Method: We use a hashmap to count the frequencies of elements in target. We then decrement the count for each element in arr. If any element in arr either doesn't exist in the hashmap or its count goes below zero, then arr cannot be transformed into target.

Both approaches have a time complexity of $O(nlogn)$ due to the sorting or $O(n)$ if we use the hashmap approach where $n$ is the length of the arrays.

If you have any further questions or need additional clarifications, feel free to ask!

24.08.04 - 1508. Range Sum of Sorted Subarray Sums

문제 링크

// 92ms, 27.2MB

class Solution {
public:
    const int MOD = 1'000'000'007;
    int rangeSum(vector<int>& nums, int n, int left, int right) {
        vector<int> sums;
        // 합을 다 안 구하고 하는 방법이 있나?
        // the sum of all non-empty continuous subarrays
        for(int i{};i<n;++i) {
            int sum{};
            for(int j{i};j<n;++j) {
                sum += nums[j];
                sums.push_back(sum);
            }
        }

        sort(begin(sums), end(sums));

        // Since the answer can be a huge number return it modulo 109 + 7. (이런 게 있더라..)
        int answer{};
        // 합쳐주는 함수가 생각이 안 난다
        for(int i{left-1};i<right;++i) {
            answer += sums[i];
            answer %= MOD;
        }
        return answer;
    }
};

gpt

The problem "Range Sum of Sorted Subarray Sums" can be broken down into several steps. Here is a detailed explanation of how to approach it:

Problem Overview

Given an integer array nums and two integers n and left and right, your task is to find the sum of the subarray sums that lie between the left-th and right-th smallest sums of all possible subarrays. The answer should be returned modulo (10^9 + 7).

Steps to Solve the Problem

  1. Generate All Subarray Sums:

    • First, generate all possible subarrays of the given array.
    • Compute the sum of each subarray.
  2. Sort the Sums:

    • Sort the array of subarray sums.
  3. Calculate the Required Sum:

    • Find the sum of elements between the indices left-1 and right-1 in the sorted array of subarray sums.
    • Return this sum modulo (10^9 + 7).

Implementation

Let's implement this step-by-step in C++:

// 90ms, 27.2MB
class Solution {
public:
    int rangeSum(std::vector<int>& nums, int n, int left, int right) {
        constexpr int MOD = 1e9 + 7;
        std::vector<int> subarraySums;

        // Generate all subarray sums
        for (int i = 0; i < n; ++i) {
            int sum = 0;
            for (int j = i; j < n; ++j) {
                sum += nums[j];
                subarraySums.push_back(sum);
            }
        }

        // Sort the subarray sums
        std::sort(subarraySums.begin(), subarraySums.end());

        // Calculate the sum from left-1 to right-1
        long long result = 0;
        for (int i = left - 1; i < right; ++i) {
            result = (result + subarraySums[i]) % MOD;
        }

        return static_cast<int>(result);
    }
};

Explanation of the Code

  1. Generate All Subarray Sums:

    • We use two nested loops to generate the sum of all subarrays.
    • For each starting point i, we calculate the sum of subarrays ending at each point j (i <= j < n).
    • These sums are stored in the subarraySums vector.
  2. Sort the Sums:

    • We use the sort function to sort the vector subarraySums.
  3. Calculate the Sum for the Given Range:

    • We iterate over the subarraySums vector from index left-1 to right-1 and compute the sum modulo (10^9 + 7).

Complexity Analysis

  • Time Complexity: Generating all subarray sums takes $O(n^2)$. Sorting the sums takes $O((n^2) \log (n^2))$. Thus, the overall time complexity is $O(n^2 \log n)$.
  • Space Complexity: We store all subarray sums, which requires $O(n^2)$ space.

This approach ensures that we efficiently compute the required range sum of sorted subarray sums.


python으로 된 완전 최적화한 코드가 있던데... C++로 바꿔달라고 요청

Certainly! Here's the given Python code converted to C++:

// 0ms, 10MB
class Solution {
public:
    int rangeSum(std::vector<int>& nums, int n, int left, int right) {
        constexpr int MOD = 1e9 + 7;

        auto count_and_sum = [&](const std::vector<int>& nums, int target) {
            int count = 0;
            long long current_sum = 0, total_sum = 0, window_sum = 0;
            int i = 0;
            for (int j = 0; j < n; ++j) {
                current_sum += nums[j];
                window_sum += static_cast<long long>(nums[j]) * (j - i + 1);
                while (current_sum > target) {
                    window_sum -= current_sum;
                    current_sum -= nums[i];
                    ++i;
                }
                count += j - i + 1;
                total_sum += window_sum;
            }
            return std::make_pair(count, total_sum);
        };

        auto sum_of_first_k = [&](const std::vector<int>& nums, int k) {
            int min_sum = *std::min_element(nums.begin(), nums.end());
            int max_sum = std::accumulate(nums.begin(), nums.end(), 0);
            int left = min_sum, right = max_sum;

            while (left <= right) {
                int mid = left + (right - left) / 2;
                if (count_and_sum(nums, mid).first >= k) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            }
            auto [count, total_sum] = count_and_sum(nums, left);
            // There can be more subarrays with the same sum of left.
            return total_sum - static_cast<long long>(left) * (count - k);
        };

        long long result = (sum_of_first_k(nums, right) - sum_of_first_k(nums, left - 1)) % MOD;
        // Ensure non-negative result
        return (result + MOD) % MOD;
    }
};

Explanation of the Code

  1. Helper Function count_and_sum:

    • This function calculates the number of subarrays whose sum is less than or equal to a given target and the total sum of such subarrays.
    • It uses a sliding window technique to maintain the sum of subarrays.
  2. Helper Function sum_of_first_k:

    • This function uses binary search to find the smallest subarray sum that has at least k subarrays.
    • It calls count_and_sum to determine the number of subarrays and their sum for a given target sum.
    • Adjusts the result to handle potential duplicates and ensure we get the sum of exactly the first k smallest subarray sums.
  3. Main Function rangeSum:

    • This function calls sum_of_first_k to get the sum of subarrays for the specified range (left to right).
    • Ensures the result is non-negative by taking it modulo (10^9 + 7).

Key Points

  • The use of lambda functions in C++ ([&] captures variables by reference) allows for defining helper functions within the main function scope, similar to Python's nested functions.
  • The auto keyword is used for type inference, simplifying the code when the exact type is complex or verbose.
  • std::make_pair and structured bindings (auto [count, total_sum]) are used for returning and unpacking multiple values from the helper functions.

내 스타일대로 변경~

class Solution {
public:
	int rangeSum(std::vector<int>& nums, int n, int left, int right) {
		using ll = long long;
		constexpr int MOD = 1e9 + 7;

		// cnt -> The number of subarrays whose sum is less than or equal to a given target.
		// totalSum -> The total sum of these subarrays.
		auto countAndSum = [&](const std::vector<int>& nums, int target) {
			int cnt{}, i{};
			ll currSum{}, totalSum{}, windowSum{};
			// currSum: The sum of the current sliding window.
			// windowSum: The sum of all subarrays ending at j that start from i to j.
			for (int j{}; j < n; ++j) {
				currSum += nums[j];
				windowSum += static_cast<ll>(nums[j]) * (j - i + 1);
				while (currSum > target) {
					// eliminate first element
					windowSum -= currSum;
					currSum -= nums[i];
					++i;
				}
				cnt += j - i + 1;
				totalSum += windowSum;
			}
			return std::make_pair(cnt, totalSum);
		};

		auto sumOfFirstK = [&](const std::vector<int>& nums, int k) {
			int min_sum = *std::min_element(begin(nums), end(nums));
			int max_sum = std::accumulate(begin(nums), end(nums), 0);
			int left = min_sum, right = max_sum;

			while (left <= right) {
				int mid = left + (right - left) / 2;
				if (countAndSum(nums, mid).first >= k) { // more than k
					right = mid - 1;
				}
				else {
					left = mid + 1;
				}
			}
			auto[cnt, totalSum] = countAndSum(nums, left);
			// There can be more subarrays with the same sum of left.
			return totalSum - static_cast<ll>(left) * (cnt - k);
		};

		ll result = (sumOfFirstK(nums, right) - sumOfFirstK(nums, left - 1)) % MOD;

		// Ensure non-negative result
		return (result + MOD) % MOD;
	}
};