最近比较闲,也比较焦虑,刷刷题吧
目录
- 11. 盛最多水的容器
- 22. 括号生成
- 31. 下一个排列
- 48. 旋转图像
- 49. 字母异位词分组
- 56. 合并区间
- 75. 颜色分类
- 79. 单词搜索
- 114. 二叉树展开为链表
- 141. 环形链表
- 148. 排序链表
- 152. 乘积最大子数组
- 169. 多数元素
- 207. 课程表(有向图排序问题)
- 215. 数组中的第K个最大元素
- 208. 实现 Trie (前缀树)
- 221. 最大正方形
- 234. 回文链表
- 238. 除自身以外数组的乘积
- 240. 搜索二维矩阵 II
- 283. 移动零
- 394. 字符串解码
- 399. 除法求值
- 406. 根据身高重建队列
- 437. 路径总和 III
- 448. 找到所有数组中消失的数字
- 543. 二叉树的直径
- 560. 和为K的子数组
11. 盛最多水的容器
这个解释挺好的
O(n) 双指针解法:理解正确性、图解原理(C++/Java)
两次遍历。
class Solution {
public:int getlen(ListNode* head){int res = 0;ListNode* cur = head;while(cur != nullptr){cur = cur->next;res++;}return res;}ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* dummy_head = new ListNode(0);dummy_head->next = head;ListNode* cur = dummy_head;int len = getlen(head);int N = len - n;for(int i = 0; i < N; i++){cur = cur->next;}ListNode* tmp = cur->next;cur->next = cur->next->next;delete(tmp);ListNode* ret = dummy_head->next;delete dummy_head;return ret;}
};
前后指针法。
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* dummy_head = new ListNode(0,head);ListNode* first = dummy_head;ListNode* second = head;//second先行n个节点for(int i = 1; i <= n ;i++){second = second->next;}//两个节点同时移动while(second){second = second->next;first = first->next;}//此时second处于链表尾部后面的空节点,first处于待删除节点的前驱ListNode* tmp = first->next;first->next = first->next->next;delete(tmp);ListNode* ret = dummy_head->next;delete dummy_head;return ret;}
};
22. 括号生成
产生左分支时候,只看当前是否还有左括号可以使用。
产生右分支时候,还要受到左分支的限制。右边剩余可以使用的括号数量一定得严格大于左边剩余的数量时,才可以产生分支
典型回溯。
class Solution {
private:vector<string> result;string path;
public:void trackback(int left,int right,string path){if(left == 0 && right == 0){result.emplace_back(path);}//剪枝if(left > right) return;//向左if(left > 0){left--;trackback(left,right,path+'(');left++;}//向右if(right > 0){right--;trackback(left,right,path+')');right++;}}vector<string> generateParenthesis(int n) {result.clear();path.clear();path = "";trackback(n,n,path);return result;}
};
31. 下一个排列
不熟悉,还得多理解理解。
class Solution {
public:void nextPermutation(vector<int>& nums) {int n = nums.size();if(n <= 1) return;int i = n-2;while(i >= 0 && nums[i] >= nums[i+1]){i--;}if(i < 0){reverse(nums.begin(),nums.end());return;}int j = n-1;while(j >= 0 && nums[i] >= nums[j]) j--;swap(nums[i],nums[j]);reverse(nums.begin()+i+1,nums.end());}
};
48. 旋转图像
草图需要画4x4的,不然具体swap的时候会搞乱掉。。。
class Solution {
public:void rotate(vector<vector<int>>& matrix) {int pos1 = 0;int pos2 = matrix.size()-1;while(pos1 < pos2){int add = 0;while(add < pos2 - pos1){int tmp = matrix[pos1][pos1+add];matrix[pos1][pos1+add] = matrix[pos2-add][pos1];matrix[pos2-add][pos1] = matrix[pos2][pos2-add];matrix[pos2][pos2-add] = matrix[pos1+add][pos2];matrix[pos1+add][pos2] = tmp;add++;}pos1++;pos2--;}}
};
49. 字母异位词分组
关键是hash表的结构。key是排序后的string,value是str数组,存放同一个key的元素。
class Solution {
public:vector<vector<string>> groupAnagrams(vector<string>& strs) {unordered_map<string,vector<string>> umap;for(auto str : strs){string key = str;sort(key.begin(),key.end());umap[key].emplace_back(str);}vector<vector<string>> result;for(auto it = umap.begin(); it != umap.end(); it++){result.emplace_back(it->second);}return result;}
};
56. 合并区间
感觉下面的这个自己的写法还是有点繁琐。。。
可以看我的每一步融合后对原数组的影响。
class Solution {
public:int his[10001];vector<vector<int>> merge(vector<vector<int>>& intervals) {if(intervals.size() == 1) return intervals;sort(intervals.begin(),intervals.end());int i = 1;vector<vector<int>> res;res.emplace_back(intervals[0]);while(i < intervals.size()){//如果前面一个区间与当前区间不重合,将此区间加入结果if(intervals[i-1][1] < intervals[i][0]){res.emplace_back(intervals[i]);}//如果前面一个和当前的重叠了,融合else if(intervals[i-1][1] >= intervals[i][0]){//融合的区间取两个区间的左右边界intervals[i][0] = min(intervals[i-1][0],intervals[i][0]);intervals[i][1] = max(intervals[i-1][1],intervals[i][1]); //然后把前面一个区间值也变为融合后的区间,具体区间长什么样可以看打印信息intervals[i-1] = intervals[i];//如果结果集最新添加的元素区间与当前区间有重合(此时可以保证改最新区间为当前区间的子区间,所以直接替换即可)if(res.back()[1] >= intervals[i][0]){res.pop_back();res.emplace_back(intervals[i]);}else res.emplace_back(intervals[i]);}//cout <<"[" << intervals[i][0]<<","<<intervals[i][1] << "]" <<endl;i++;}return res;}
};
这边贴一下甜姨的解法,以及她整理的相关题目,留着以后再刷:
吃🐳!🤷♀️竟然一眼秒懂合并区间!
75. 颜色分类
class Solution {
public:void sortColors(vector<int>& nums) {int size = nums.size();if(size < 2) return;int zero = 0;int two = size;int i = 0;while(i < two){if(nums[i] == 0){swap(nums[zero],nums[i]);zero++;i++;}else if(nums[i] == 1){i++;}else{two--;swap(nums[i],nums[two]);}}return;}
};
79. 单词搜索
回溯法,类似的题有120、200
class Solution {
public:int direction[5] = {-1,0,1,0,-1};bool dfs(vector<vector<char>>& board,vector<vector<bool>>& visited,string word,int index,int i,int j){if(index == word.size()-1) return board[i][j] == word[index];if(board[i][j] == word[index]){visited[i][j] = true;for(int k = 0; k < 4; k++){int x = i + direction[k];int y = j + direction[k+1];if(x >= 0 && x < board.size() && y >=0 && y < board[0].size() && visited[x][y] == false){if(dfs(board,visited,word,index+1,x,y) == true) return true;}}visited[i][j] = false;}return false;}bool exist(vector<vector<char>>& board, string word) {int m = board.size();int n = board[0].size();vector<vector<bool>> visited(m,vector<bool>(n,false));for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){if(dfs(board,visited,word,0,i,j) == true) return true;}}return false;}
};
114. 二叉树展开为链表
class Solution {
public:vector<TreeNode*> num;void preorder(TreeNode* root){num.emplace_back(root);if(root->left) preorder(root->left);if(root->right) preorder(root->right);}void flatten(TreeNode* root) {num.clear();if(root == nullptr) return;preorder(root);for(int i = 1; i < num.size(); i++){TreeNode* prev = num[i-1];TreeNode* cur = num[i];prev->right = cur;prev->left = nullptr;}}
};
141. 环形链表
快慢指针法
class Solution {
public:bool hasCycle(ListNode *head) {ListNode* slow = head;ListNode* fast = head;while(slow && fast && fast->next){slow = slow->next;fast = fast->next->next;if(slow == fast) return true;}return false;}
};
148. 排序链表
getmid和merge子函数要好好写。关于递归调用的顺序也要注意。
这个图很好,可以很好说明思路
/*** 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 {
private:ListNode* getmiddleNode(ListNode* head){if(head == nullptr || head->next == nullptr)return head;ListNode* slow = head;ListNode* fast = head->next->next;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}return slow;}ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {ListNode* dummy_head = new ListNode(-1); ListNode* cur = dummy_head;while(l1 != nullptr && l2 != nullptr){if(l1->val > l2->val){cur->next = l2;l2 = l2->next;cur = cur->next;}else{cur->next = l1;l1 = l1->next;cur = cur->next;}}while(l1 != nullptr){cur->next = l1;l1 = l1->next;cur = cur->next;}while(l2 != nullptr){cur->next = l2;l2 = l2->next;cur = cur->next;}ListNode* ret = dummy_head->next;delete dummy_head;return ret;}
public:ListNode* sortList(ListNode* head) {//if(head == nullptr || head->next == nullptr)return head;//ListNode* midNode = getmiddleNode(head);ListNode* righthead = midNode->next;midNode->next = nullptr;//ListNode* left = sortList(head);ListNode* right = sortList(righthead);//return mergeTwoLists(left,right);}
};
152. 乘积最大子数组
class Solution {
public:int maxProduct(vector<int>& nums) {int n = nums.size();vector<int> maxn(n,INT_MIN);vector<int> minn(n,INT_MAX);maxn[0] = minn[0] = nums[0];int res = nums[0];for(int i = 1; i < n; i++){if(nums[i] > 0){maxn[i] = max(nums[i],maxn[i-1] * nums[i]);minn[i] = min(nums[i],minn[i-1] * nums[i]);}else{maxn[i] = max(nums[i],minn[i-1] * nums[i]);minn[i] = min(nums[i],maxn[i-1] * nums[i]);}res = max(res,maxn[i]);}return res; }
};
169. 多数元素
这一题的投票法比较妙。
投票法,众数个数至少比非众数多一,把COUNT加减当作一个众数抵消掉一个非众数,剩下的一定是众数。
class Solution {
public:int majorityElement(vector<int>& nums) {int res = -1;int count = 0;for(int i = 0; i < nums.size(); i++){if(count == 0) res = nums[i];if(res != nums[i]) count--;else count++;}return res;}
};
207. 课程表(有向图排序问题)
将一个有向无环图转成线性的排序就叫拓扑排序。
每次只能选入度为0的课,因为它不依赖于其他课,是当下能上的课。
BFS:
1、让入度为0的课入列,它们是能直接选的课
2、然后逐个出列,出列代表着课被选,需要减少相关课的入度
3、如果相关课的入度变为0,安排它入列
每门课的入度需要被记录,我们关心入度值得变化。
课程之间得依赖关系也要被记录,我们关心选当前课会减少哪些课得入度
所以我们准备入度数组:
课号0->n-1作为索引,通过遍历先决条件求出对应得初始入度
邻接表:用哈希表记录依赖关系
key:课号
value:依赖于这门课得后续课,放入一个数组中
判断能否修完所有课:
用一个变量count记录入列得顶点个数,最后判断count是否等于总课程数
class Solution {
public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {//每个节点得入度,即vector<int> rudu(numCourses);unordered_map<int,vector<int>> rely_course;for(int i = 0; i < prerequisites.size(); i++){//得到每个节点得初始入度rudu[prerequisites[i][0]]++;//记录依赖关系,注意这里记录得是该节点的出节点rely_course[prerequisites[i][1]].push_back(prerequisites[i][0]);}//记录已经入列的顶点个数int count = 0; queue<int> que;//将初始入度值为0的顶点送入队列中for(int i = 0; i < numCourses; i++){if(rudu[i] == 0) que.push(i);}while(!que.empty()){int now = que.front();que.pop();count++;//对该顶点的出节点进行遍历for(int i = 0; i < rely_course[now].size(); i++){rudu[rely_course[now][i]]--;if(rudu[rely_course[now][i]] == 0) que.push(rely_course[now][i]);}}if(count == numCourses) return true;else return false;}
};
215. 数组中的第K个最大元素
topk问题,姊妹问题为牛客网的最小的k个数。
求最大K,用降序排列的优先队列priority_queue<int,vector<int>,greater<int>> que;
求最小K,用升序排列的优先队列priority_queue<int> que;
class Solution {
public:int findKthLargest(vector<int>& nums, int k) {priority_queue<int, vector<int>, greater<int> > que;//入堆for(int i = 0; i < k; i++)que.push(nums[i]);//与堆顶元素比较,堆顶元素是最小的,这样比较得到的就是最大的前K个数,最小的就是第K个数了for(int i = k; i < nums.size(); i++){if(nums[i] > que.top()){que.pop();que.push(nums[i]);}}return que.top();}
};
208. 实现 Trie (前缀树)
这篇讲解很到位
Trie Tree 的实现 (适合初学者)
class Trie {
private:bool ifEnd;Trie* next[26];
public:/** Initialize your data structure here. */Trie() {this->ifEnd = false;for(int i = 0; i < 26; i++)this->next[i] = nullptr; }/** Inserts a word into the trie. */void insert(string word) {Trie* node = this;for(int i = 0; i < word.size(); i++){int c = word[i] - 'a';if(node->next[c] == nullptr)node->next[c] = new Trie();node = node->next[c];}node->ifEnd = true;}/** Returns if the word is in the trie. */bool search(string word) {Trie* node = this;for(int i = 0; i < word.size(); i++){int c = word[i] - 'a';if(node->next[c] == nullptr)return false;node = node->next[c];}return node->ifEnd;}/** Returns if there is any word in the trie that starts with the given prefix. */bool startsWith(string prefix) {Trie* node = this;for(int i = 0; i < prefix.size(); i++){int c = prefix[i] - 'a';if(node->next[c] == nullptr)return false;node = node->next[c];}return true;}
};
221. 最大正方形
dp法:
使用动态规划降低时间复杂度,用dp(i,j)表示以(i,j)为右下角,且只包含1地正方形地边长最大值。
如果能计算出所有dp(i,j)的值,那么其中的最大值即为矩阵中只包含1的正方形的边长最大值。
其平方和为最大正方形的面积。
if matrix[i][j] == 0 => dp(i,j) = 0
if matrix[i][j] == 1 => dp(i,j) = min(dp(i-1,j),dp(i-1,j-1),dp(i,j-1)+1
边界条件:
i == 0 || j == 0,则dp(i,j) = 1
class Solution {
public:int maximalSquare(vector<vector<char>>& matrix) {int n = matrix.size();int m = matrix[0].size();if(n == 0 || m == 0) return 0;int maxVal = 0;vector<vector<int>> dp(n,vector<int>(m,0));//递推 + 初始化for(int i = 0; i < n; i++){for(int j = 0; j < m; j++){if(matrix[i][j] == '1'){if(i == 0 || j == 0)dp[i][j] = 1;else dp[i][j] = min(dp[i-1][j],min(dp[i-1][j-1],dp[i][j-1])) + 1; }elsedp[i][j] = 0;maxVal = max(maxVal,dp[i][j]);}}return maxVal*maxVal;}
};
234. 回文链表
思路:
1、先使用快慢指针找到链表的中间节点,也就是将链表分为前后两个链表
2、将后面的链表进行反转
3、比较两个链表是否相同
/*** 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* getMidNode(ListNode* head){if(head == nullptr || head->next == nullptr)return head;ListNode* slow = head;ListNode* fast = head->next->next;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}return slow;}ListNode* reverseList(ListNode* head){if(head == nullptr || head->next == nullptr) return head;ListNode* prev = nullptr;ListNode* cur = head;while(cur){ListNode* tmp = cur->next;cur->next = prev;prev = cur;cur = tmp;}return prev;}bool isPalindrome(ListNode* head) {ListNode* first = head;ListNode* bef_second = getMidNode(head)->next;ListNode* second = reverseList(bef_second);while(first && second){if(first->val != second->val) return false;first = first->next;second = second->next;}return true;}
};
238. 除自身以外数组的乘积
只开辟一个右边乘积数组,另外左边乘积在for循环种计算。
class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {int n = nums.size();;vector<int> L(n,1);for(int i = nums.size()-1; i >= 0; i--){if(i == nums.size()-1) L[i] = 1;else L[i] = L[i+1]*nums[i+1]; //cout << L[i] << endl;}int R = 1;vector<int> result(n);for(int i = 0; i < nums.size(); i++){result[i] = R * L[i];R *= nums[i]; }return result;}
};
240. 搜索二维矩阵 II
从左下角往右上搜索。
若当前矩阵的元素值 == target,则直接返回 true。
若当前矩阵的元素值 > target,则向上移动一行列不变,即 matrix[i][j] 变为 matrix[i - 1][j],继续进行比较。
若当前矩阵的元素值 < target,则向右移动一列行不变,即 matrix[i][j] 变为 matrix[i][j + 1],继续进行比较。
class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int n = matrix.size();int m = matrix[0].size();int hang = n - 1;int lie = 0;while(lie < m && hang >= 0){if(target == matrix[hang][lie]) return true;else if(target > matrix[hang][lie]) lie++;else hang--;}return false;}
};
283. 移动零
与75颜色分类类似。不太熟悉。
使用双指针法,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。
右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。
左指针左边均为非0数
右指针左边知道左指针处均为0,所以每次交换都是将左值帧的0与右指针的非零交换。
class Solution {
public:void moveZeroes(vector<int>& nums) {if(nums.size() <= 1) return;int left = 0;for(int right = 0; right < nums.size(); right++){if(nums[right] != 0){swap(nums[left],nums[right]);left++;}}}
};
394. 字符串解码
把字母、数字、括号看成独立的TOKEN,并用栈来维护这些TOKEN。
遍历数组:
1、如果当前的字符为数位,解析出一个数字(连续的多个数位)并进栈
2、如果当前的字符为字母或者左括号,直接进栈
3、如果当前字符为右括号,开始出栈,一直到左括号出栈,出栈序列反转后拼接成一个字符串,此时取出栈顶的数字,就是这个字符串应该出现的次数,根据次数和字符串构造出新的字符串并进栈。
将栈中的元素按照从栈底到栈顶的顺序拼接起来,就得到了答案。
class Solution {
public:string decodeString(string s) {string ans = "";stack<int> numStack;stack<string> ansStack;int num = 0;for(char c : s){//如果是数字if(c >= '0' && c <= '9') num = num*10+c-'0';//如果是左括号,将之前的结果清算一下else if(c == '['){ansStack.push(ans);numStack.push(num);ans = "";num = 0;}//如果是字符,拼接字符串else if(c >= 'a' && c <= 'z')ans += c;//如果是右括号,出栈结算else{string ans_tmp = ansStack.top();ansStack.pop();int num_tmp = numStack.top();numStack.pop();while(num_tmp--){ans_tmp += ans;}ans = ans_tmp;}}return ans;}
};
399. 除法求值
考察图的深搜回溯以及一些复杂数据结构的构建。
class Solution {
public:vector<double> res;bool ifFind;void dfs(unordered_map<string,vector<pair<string,double>>>& umap,unordered_map<string,int>& visited, string& now, string& target,double path){if(ifFind == false) return;if(now == target){ifFind = false;res.emplace_back(path);return;}//对和该节点相连的每个节点进行深搜for(int i = 0; i < umap[now].size(); i++){if(visited[umap[now][i].first] == 0){visited[umap[now][i].first] = 1;dfs(umap,visited,umap[now][i].first,target,path*umap[now][i].second);visited[umap[now][i].first] = 0;}}return;}vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {unordered_map<string,vector<pair<string,double>> > umap;unordered_map<string,int> visited;//将每个节点与相连节点的边的权值计算出来for(int i = 0; i < equations.size(); i++){umap[equations[i][0]].emplace_back( make_pair(equations[i][1],values[i]) );umap[equations[i][1]].emplace_back( make_pair(equations[i][0],1.0/values[i]) );}//对每个节点进行深搜for(int i = 0; i < queries.size(); i++){if(umap.find(queries[i][0]) == umap.end()){res.emplace_back(-1.0);}else{ifFind = true;dfs(umap,visited,queries[i][0],queries[i][1],1);if(ifFind) res.emplace_back(-1.0);}}return res;}
};
406. 根据身高重建队列
class Solution {
public:vector<vector<int>> reconstructQueue(vector<vector<int>>& nums) {int n = nums.size();vector<vector<int>> ans;sort(nums.begin(),nums.end(),[](const vector<int>& a,const vector<int>& b){//[0]降序,若相等,[1]升序if(a[0] != b[0])return a[0] > b[0];return a[1] < b[1];}); for(int i = 0; i < nums.size(); i++){//结果集中元素个数大于第i个人前面应该有的人数时,将第i个人插入到结果集的[i][1]位置if(ans.size() > nums[i][1])ans.insert(ans.begin()+nums[i][1],nums[i]);//结果集中元素个数等于第i个人前面应有的人数时,将第i个人追加到结果集后面。elseans.emplace_back(nums[i]);}return ans;}
};
437. 路径总和 III
巧妙使用前缀和,思路主要看注释,就是回溯+前缀和Map。与下面的560有相似的思想
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int target;unordered_map<int,int> curSumMap; //保存前缀树,key为根节点到此节点的前缀和,value为该前缀和出现的次数int dfs(TreeNode* node,int curSum){if(node == nullptr) return 0;int ans = 0;curSum += node->val; //得到当前前缀树的值//两节点间的路径和 = 两节点的前缀和之差,所以当前节点的路径和减去目标值的路径和就等于其某个祖先节点的路径和,观察有几个这样的祖先节点。ans += curSumMap[curSum - target]; //得到我们想要前缀树的个数,想要前缀树值就是当前前缀树值减去目标值curSumMap[curSum] += 1; //将当前前缀树的值保存,前缀和为curSum的节点个数+1//搜索左右子节点ans += dfs(node->left,curSum);ans += dfs(node->right,curSum);curSumMap[curSum] -= 1; //防止左边前缀树影响右边前缀树,左边前缀树可能有个为6,右边正好想要一个前缀树为6的,这样子就出错了return ans; //结果是当前节点前缀树的个数加上左边满足的个数加右边满足的个数}int pathSum(TreeNode* root, int targetSum) {target = targetSum;curSumMap[0] = 1; //前缀树为0的个数至少是一个return dfs(root,0);}
};
448. 找到所有数组中消失的数字
原地哈希。不算简单。
class Solution {
public:vector<int> findDisappearedNumbers(vector<int>& nums) {for(int i = 0; i < nums.size(); i++){int x = (nums[i]-1) % nums.size();nums[x] += nums.size(); }vector<int> res;for(int i = 0; i < nums.size(); i++){if(nums[i] <= nums.size()) res.emplace_back(i+1);}return res;}
};
543. 二叉树的直径
先求每个节点的左右子节点的最大深度,然后加起来的值和maxlen比较更新。然后更新当前节点的最大深度。
class Solution {
public:int maxlen = 0;int getDepth(TreeNode* node){if(node == NULL) return 0;int left=getDepth(node->left);int right=getDepth(node->right);maxlen = max(maxlen,left+right);return max(left,right)+1;}int diameterOfBinaryTree(TreeNode* root) {if(!root->left && !root->right) return 0;getDepth(root);return maxlen;}
};
560. 和为K的子数组
求[j…i]子数组和为k,可以转化为
pre[i] - pre[j-1] == k
移项后:
pre[j-1] == pre[i] - k
考虑以i结尾的和为k的连续子数组个数只要统计有多少个前缀和为pre[i] - k的pre[j]即可。
哈希表umap,以和为key,出现的次数为value。
从左往右边更新umap边计算答案。
class Solution {
public:int subarraySum(vector<int>& nums, int k) {unordered_map<int,int> umap;umap[0] = 1;int count = 0;int pre = 0;for(int i = 0; i < nums.size(); i++){pre += nums[i];if(umap.find(pre - k) != umap.end()){count += umap[pre- k];}umap[pre]++;}return count;}
};