1 前缀和 1 2 3 4 vector<int > prefSum {nums[0 ]}; for (int  i = 1 ; i < nums.size (); ++i) {    prefSum[i] += (nums[i] + prefSum.back ());  } 
 
1546最大非重叠数组 1 题目 https://leetcode-cn.com/problems/maximum-number-of-non-overlapping-subarrays-with-sum-equals-target/submissions/ 
2 解题思路 最为关键的一句话: 每次找结束序号最小的和为target的子数组,然后从这个子数组的后面开始搜寻下一个子数组,经典贪心。
前缀和,普通为o(n^2),使用hash优化: subSum[j:i],本来需要遍历所有的j找出为k的subarray, 但是换个思路:  其实就是找i之前,有多少个前缀和为 preSum[j] - k, 那么我们把前缀和用hash存一下,那不就能够很快找到了?
但是有一个问题,在下一次搜寻开始的时候,需要将上一次搜寻过程的hash清零, 否则上一次的hash的结果会影响当前子序和。 而且假设上一次搜寻到j了,那么这次从j+1开始搜寻,必须保证前缀和也是从j+1开始
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class  Solution  {public :    int  maxNonOverlapping (vector<int >& nums, int  target)   {         int  ans = 0 ;                                                                                                                                                int  st = 0 ;         int  ed = 0 ;         int  lastFoundEd = ed;                           while (st < nums.size ()) {             ed = st;                          unordered_set<int > hash = {0 };             int  curSumFromLastFoundEd = 0 ;             while (ed < nums.size ()) {                 curSumFromLastFoundEd += nums[ed];                 if (hash.count (curSumFromLastFoundEd - target)) {                     ++ans;                     st = ed;                             break ;                 } else  {                     hash.insert (curSumFromLastFoundEd);                 }                 ++ed;             }             ++st;         }         return  ans;     } }; 
 
0560subArraySum 子数组和为k 1 题目 https://leetcode-cn.com/problems/subarray-sum-equals-k/ 
2 解题思路 前缀和,普通为o(n^2),使用hash优化: subSum[j:i],本来需要遍历所有的j找出为k的subarray, 但是换个思路:  其实就是找i之前,有多少个前缀和为 preSum[j] - k, 那么我们把前缀和用hash存一下,那不就能够很快找到了?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class  Solution  {public :    int  subarraySum (vector<int >& nums, int  k)   {         vector<int > prefSum (nums.size())  ;         prefSum[0 ] = nums[0 ];         for (int  i = 1 ; i < nums.size (); ++i) {             prefSum[i] += (nums[i] + prefSum[i-1 ]);          }         int  st = 0 ;         int  ed = 0 ;         int  ans = 0 ;         int  curSum = 0 ;         std::unordered_map<int , int > hash;         hash[0 ] = 1 ;         while (ed < nums.size ()) {             if (hash.find (prefSum[ed] - k) != hash.end ()) {                 ans += hash[prefSum[ed] - k];             }              hash[prefSum[ed]]++;                                                                                                        ++ed;         }                  return  ans;     } }; 
 
1171移除和为0的子链表 1 题目: https://leetcode-cn.com/problems/remove-zero-sum-consecutive-nodes-from-linked-list/ 
2 解题思路: 个人暴力思路:
1 每次移除一个和为0的子数组,返回一个新的链表 
2 重复上述过程直到没有和为0的子数组 
 
前缀和思路参考:采用前缀和判断和为0方法 : 我们可以考虑如果给的入参不是链表是数组的话,只需要求出前缀和,对于前缀和相同的项,那他们中间的部分即是可以消除掉的,比如以 [1, 2, 3, -3, 4] 为例,其前缀和数组为 [1, 3, 6, 3, 7] ,我们发现有两项均为 3,则 6 和 第二个 3 所对应的原数组中的数字是可以消掉的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class  Solution  {public :    ListNode* newHead;     ListNode* removeZeroSumSublists (ListNode* head)   {         newHead = head;         while (removeOneZeroSubList (newHead)){ }         return  newHead;     }     bool  removeOneZeroSubList (ListNode* newHead)   {         vector<int > valVec;         ListNode* head = newHead;         ListNode* p = head;         while (p != nullptr ) {             valVec.emplace_back (p->val);             p = p->next;         }         size_t  len = valVec.size ();         vector<vector<int >> sumMat (len, vector <int >(len));                           ListNode* stPtr = head;         ListNode* lastStPtr = nullptr ;         for (int  st = 0 ; st < len; ++st) {             sumMat[st][st] = valVec[st];             if (sumMat[st][st] == 0 ) {                 if (nullptr  == lastStPtr) {                     this ->newHead = head->next;                     return  true ;                 }                 lastStPtr->next = stPtr->next;                 return  true ;             }             ListNode* edPtr = stPtr->next;             for (int  ed = st + 1 ; ed < len; ++ed) {                 sumMat[st][ed] = sumMat[st][ed-1 ] + valVec[ed];                 if (sumMat[st][ed] == 0 ) {                     if (nullptr  == lastStPtr) {                         this ->newHead = edPtr->next;                         return  true ;                     }                     lastStPtr->next = edPtr->next;                     return  true ;                 }                 edPtr = edPtr->next;             }             lastStPtr = stPtr;             stPtr = stPtr->next;         }         return  false ;     } }; 
 
1292最大方块长度 1 题目 https://leetcode-cn.com/problems/maximum-side-length-of-a-square-with-sum-less-than-or-equal-to-threshold/ 
2 解题思路 
1 建立二维前缀和: 1 2 3 4 5 6   vector<vector<int >> preSum (m+1 , vector <int >(n+1 , 0 )); for (int  i = 1 ; i < m+1 ; ++i) {    for (int  j = 1 ; j < n+1 ; ++j) {         preSum[i][j] = preSum[i-1 ][j] + preSum[i][j-1 ] - preSum[i-1 ][j-1 ] + mat[i-1 ][j-1 ];     } } 
 
2 遍历所有边长的正方形即可(每个正放形为起点加上边长),遍历长度的过程可以通过二分搜索加速 
 
值得思考的点: 如何快速得知当前位置是不是被阻挡了? 使用unordered_set作为hash快速查找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class  Solution  {public :    int  maxSideLength (vector<vector<int >>& mat, int  threshold)   {                           int  m = mat.size ();         int  n = mat[0 ].size ();         vector<vector<int >> preSum (m+1 , vector <int >(n+1 , 0 ));         for (int  i = 1 ; i < m+1 ; ++i) {             for (int  j = 1 ; j < n+1 ; ++j) {                 preSum[i][j] = preSum[i-1 ][j] + preSum[i][j-1 ] - preSum[i-1 ][j-1 ] + mat[i-1 ][j-1 ];             }         }                  int  maxSquareLen = std::min (m, n);                                                      int  stLen = 1 ;         int  edLen = maxSquareLen;         int  ans = 0 ;         while (stLen <= edLen) {             int  len = (stLen + edLen) / 2 ;             bool  found = false ;             for (int  i = 0 ; i <= m - len; ++i) {                 for (int  j = 0 ; j <= n - len; ++j) {                     if (getRec (preSum, i+1 , j+1 , i + len, j + len) <= threshold) {                         found = true ;                     };                 }             }                        if (found) {                  stLen = len+1 ;                 ans = len;             } else  {                  edLen = len-1 ;             }                    }         return  ans;     }     int  getRec (vector<vector<int >>& preSum, int  i, int  j, int  m, int  n)   {         return  preSum[m][n] - preSum[m][j-1 ] - preSum[i-1 ][n] + preSum[i-1 ][j-1 ];     } }; 
 
1124 良好表现的最长时间段 1 题目 https://leetcode-cn.com/problems/longest-well-performing-interval/ 
2 解题思路 较为容易想到前缀和思路: 不好想的地方在于第1和3条,思路如下:
1 对于这种良好费良好的判断,我们需要把数组转换成 -1, 1的数组 
2 对上述数组作前缀和 
3 那么对于每个到来的j,只需要找到最小的i,满足 preSum[j] - preSum[i] == 1即可
3.1 如何理解最小的i,也就是说,对于同一个preSum值的下标,我们总是去最小的i即可 
3.2 对于 9 9 9 9 9这种全正常的思路,如何判断? 前缀和的值本身就可以判断,大于零的下标都可以是良好工作区间 
 
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class  Solution  {public :    int  longestWPI (vector<int >& hours)   {         vector<int > preSum = {0 };         for (int  i = 0 ; i < hours.size (); ++i) {             preSum.emplace_back ((hours[i] > 8  ? 1  : -1 ) + preSum.back ());         }                    int  st = 0 ;         int  ed = 0 ;         int  res = INT_MIN;                  map<int , int > m;         m[0 ] = 0 ;         int  lastPop = 0 ;         vector<int > mono = {0 };         for (; ed < hours.size (); ++ed) {             if  (preSum[ed + 1 ] > 0 ) {                 res = std::max (res, ed + 1 );                 continue ;             }             map<int , int >::iterator it = m.find (preSum[ed + 1 ] - 1 );             if (it != m.end ()) {                 res = std::max (ed - it->second, res);             }              if  (m.find (preSum[ed + 1 ]) == m.end ()) {                 m[preSum[ed + 1 ]] = ed;              }                      }         return  res < 0  ? 0  : res;     } };