# [LeetCode 363. Max Sum of Rectangle No Larger Than K](https://leetcode.com/explore/challenge/card/july-leetcoding-challenge-2021/608/week-1-july-1st-july-7th/3801/) ### Daily challenge Jul 3, 2021 (HARD) >Given an **`m x n`** matrix **`matrix`** and an integer **`k`**, return the max sum of a rectangle in the matrix such that its sum is no larger than k. > >It is **guaranteed** that there will be a rectangle with a sum no larger than k. ![](https://i.imgur.com/PqHhFgm.png) :::info **Example 1:** **Input:** matrix = [[1,0,1],[0,-2,3]], k = 2 **Output:** 2 **Explanation:** Because the sum of the blue rectangle [[0, 1], [-2, 3]] is 2, and 2 is the max number no larger than k (k = 2). ::: :::info **Example 2:** **Input:** matrix = [[2,2,-1]], k = 3 **Output:** 3 ::: :::warning **Constraints:** * m == matrix.length * n == matrix[i].length * 1 <= m, n <= 100 * -100 <= matrix[i][j] <= 100 * -105 <= k <= 105 ::: --- ### Approach 1 : Kadane Algorithm :book: **`1064 ms ( 62.09% )`** **`O( min(m,n)^2 * max(m,n) * log(max(m,n)))`** :::danger **Kadane Algorithm** is a kind of DP approach and it can solve *`Maximum Sum Rectangular Submatrix in Matrix`*. :movie_camera: [Easily Understanding Video](https://www.youtube.com/watch?v=yCQN096CwWM) :movie_camera: ::: #### **Kadane Algorithm** >1. 與 Sliding Window 相似,使用兩個 pointer ( left & right ),分別表示開始、結束位置,並將 **`每列的`** 計算結果存入 `SUM`。 >2. 從 `SUM` 中計算最大的總和。 >e.g. SUM = {2, 0, 2, -3}, maxSum = 2 + 0 + 2 = 4。 >>如何尋找 ? >>* 將 `SUM` 從頭開始進行累加,並記錄當前總和 **`current = max(0, current)`** 以及最大值 **`MAX = max(current, MAX)`**。 >>* 若陣列內皆為 `負數` 則需要特別判斷 ---> 回傳陣列中的`最大值`即可。 >```cpp= >class Kadanes{ > public static int GetMax(int[] SUM){ > // 無考慮皆為負數的狀況 // > int current = 0; > int MAX = SUM[0]; > for (int i = 0; i < SUM.size(); i++){ > current += SUM[i]; > current = max(0, current); > MAX = max(current, MAX); > } > > return MAX; > } >}; >``` #### 但是題目要求 No Larger Than K。 >需將 **Kadane Algorithm** 方法改進。 >* 紀錄所有的 `current` 存入 `set` 當中 ( 不使用 `max` 更改 `current` )。 >* 因為要找到 **`小於等於 K`** 的值,使用 **`set.lower_bound(current_sum - k)`** 找出是否有符合的答案。 >:::danger >Why we use **`lower_bound(current_sum - k)`** ? > >:::spoiler >| index | SUM | set | >|:---:|:---:|:---:| >| [0] | 3 | 3 | >| [1] | 7 | 10 | >| [2] | 8 | **current** | > >Assume **K = 16**。 >當 `i = 2` 時,`current = 10 + 8 = 18`雖然是最大值,但超過要求的 K = 16。 >根據公式 : >$$ >set(i) - set(j) \le K >$$ >其中 `i` 為當前位置,若能找到一個 `j` 使答案最接近 `K`,該值就是所求的答案。 > >將 `K`, `set(j)` 移項後,可以推測出如果使用 **`lower_bound(current - k)`** 尋找 **`第一個大於等於 current - k`** 的 `set(j)`,就非常可能是我們想要的答案。 >* **`set(j) >= current`** ---> **`current - set(j) <= 0`** >* **`set(j) < current`** ---> **`current - set(j) > 0`** 有可能是答案 :100: > >以上表格為例 : >>**`i = 2, current = 18`** -> **`lower_bound(current - K) = 3`**。 >>**`ans = max(ans, current - 3) = 15。`** >>可以推斷出當 `Rectangle` 是由 `[1]、[2]` 組成時,會有最大的答案。 >::: > > > > >```cpp=20 >// find ans >set<int > record; >record.insert(0); >int current_sum = 0 > >for(int sum : kadane){ > current_sum += sum; > auto it = record.lower_bound(current_sum - k); > if(it != record.end()) ans = max(ans, current_sum - *it); > record.insert(current_sum); >} >``` >:::success >```cpp=22 >record.insert(0); >``` >先加入 `0` 以避免 `第一項` 即為答案。 >::: ```cpp=1 class Solution { public: int maxSumSubmatrix(vector<vector<int>>& matrix, int k) { if(matrix.empty()) return 0; int row = matrix.size(); int col = matrix[0].size(); int ans = INT_MIN; for(int left=0; left<col; left++){ // reset vector vector<int > kadane(row, 0); for(int right=left; right<col; right++){ // kadane algorithm -> count each col's sum for(int i=0; i<row; i++){ kadane[i] += matrix[i][right]; } // find ans set<int > record; record.insert(0); int current_sum = 0 for(int sum : kadane){ current_sum += sum; auto it = record.lower_bound(current_sum - k); if(it != record.end()) ans = max(ans, current_sum - *it); record.insert(current_sum); } } } return ans; } }; ```