c++ leetcode 500-600

朴灿烈づ我的快乐病毒、 2023-07-20 13:44 96阅读 0赞

文章目录

  • 重做题 501 ,502,507,508,509,516,517,519,523,524,525,526,528,530,531,538,539,540到563全部丢失,564
    1. 键盘行
    1. 二叉搜索树中的众数
    1. IPO
    1. 下一个更大元素 II(单调栈)
    1. 相对名次
    1. 完美数
    1. 出现次数最多的子树元素和
    1. 斐波那契数(记忆化)
    1. 二叉搜索树中的中序后继 II
    1. 找树左下角的值
    1. 在每个树行中找最大值
    1. 最长回文子序列(dp********************)
    1. 超级洗衣机
    1. 零钱兑换 II
    1. 随机翻转矩阵
    1. 检测大写字母
    1. 连续的子数组和
    1. 通过删除字母匹配到字典里最长单词
    1. 连续数组
    1. 优美的排列
    1. 按权重随机选择
    1. 二叉搜索树的最小绝对差
    1. 孤独像素 I
    1. 数组中的K-diff数对
    1. 从字符串生成二叉树
    1. 把二叉搜索树转换为累加树
    1. 最小时间差(先排序)
    1. 01 矩阵(dfs,bfs)
    1. 二叉树的直径
    1. 朋友圈(并查集)
    • 并查集 https://blog.csdn.net/zjy\_code/article/details/80634149
    1. 和为K的子数组
    1. 寻找最近的回文数
    1. 字符串的排列
    1. 另一个树的子树
    1. 出界的路径数
    1. 两个字符串的删除操作
    1. 最长和谐子序列(哈希)

重做题 501 ,502,507,508,509,516,517,519,523,524,525,526,528,530,531,538,539,540到563全部丢失,564

500. 键盘行

  1. class Solution {
  2. public:
  3. vector<string> findWords(vector<string>& words) {
  4. unordered_map<char,int> mp={
  5. {
  6. 'q',0},{
  7. 'w',0},{
  8. 'e',0},{
  9. 'r',0},{
  10. 't',0},{
  11. 'y',0},{
  12. 'u',0},{
  13. 'i',0},{
  14. 'o',0},{
  15. 'p',0},{
  16. 'a',1},{
  17. 's',1},{
  18. 'd',1},{
  19. 'f',1},{
  20. 'g',1},{
  21. 'h',1},{
  22. 'j',1},{
  23. 'k',1},{
  24. 'l',1},{
  25. 'z',2},{
  26. 'x',2},{
  27. 'c',2},{
  28. 'v',2},{
  29. 'b',2},{
  30. 'n',2},{
  31. 'm',2},{
  32. 'Q',0},{
  33. 'W',0},{
  34. 'E',0},{
  35. 'R',0},{
  36. 'T',0},{
  37. 'Y',0},{
  38. 'U',0},{
  39. 'I',0},{
  40. 'O',0},{
  41. 'P',0},{
  42. 'A',1},{
  43. 'S',1},{
  44. 'D',1},{
  45. 'F',1},{
  46. 'G',1},{
  47. 'H',1},{
  48. 'J',1},{
  49. 'K',1},{
  50. 'L',1},{
  51. 'Z',2},{
  52. 'X',2},{
  53. 'C',2},{
  54. 'V',2},{
  55. 'B',2},{
  56. 'N',2},{
  57. 'M',2}};
  58. vector<string> res;
  59. for(auto&w:words)
  60. {
  61. bool b = true;
  62. for(int i = 0;i<w.size()-1;i++)
  63. {
  64. if(mp[w[i]]!=mp[w[i+1]]){
  65. b=false;break;}
  66. }
  67. if(b)res.push_back(w);
  68. }
  69. return res;
  70. }
  71. };

501. 二叉搜索树中的众数

思路:二叉搜索树的中序遍历是一个升序序列,逐个比对当前结点(root)值与前驱结点(pre)值。更新当前节点值出现次数(curTimes)及最大出现次数(maxTimes),更新规则:若curTimes=maxTimes,将root->val添加到结果向量(res)中;若curTimes>maxTimes,清空res,将root->val添加到res,并更新maxTimes为curTimes。

作者:junstat
链接:https://leetcode-cn.com/problems/find-mode-in-binary-search-tree/solution/er-cha-sou-suo-shu-zhong-de-zhong-shu-by-junstat/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  1. void inOrder(TreeNode* root, TreeNode*& pre, int& curTimes,
  2. int& maxTimes, vector<int>& res){
  3. if (!root) return;
  4. inOrder(root->left, pre, curTimes, maxTimes, res);
  5. if (pre)
  6. curTimes = (root->val == pre->val) ? curTimes + 1 : 1;
  7. if (curTimes == maxTimes)
  8. res.push_back(root->val);
  9. else if (curTimes > maxTimes){
  10. res.clear();
  11. res.push_back(root->val);
  12. maxTimes = curTimes;
  13. }
  14. pre = root;
  15. inOrder(root->right, pre, curTimes, maxTimes, res);
  16. }
  17. vector<int> findMode(TreeNode* root) {
  18. vector<int> res;
  19. if (!root) return res;
  20. TreeNode* pre = NULL;
  21. int curTimes = 1, maxTimes = 0;
  22. inOrder(root, pre, curTimes, maxTimes, res);
  23. return res;
  24. }
  25. 作者:junstat
  26. 链接:https://leetcode-cn.com/problems/find-mode-in-binary-search-tree/solution/er-cha-sou-suo-shu-zhong-de-zhong-shu-by-junstat/
  27. 来源:力扣(LeetCode
  28. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

502. IPO

  1. class Solution {
  2. public:
  3. int findMaximizedCapital(int k, int W, vector<int>& Profits, vector<int>& Capital) {
  4. priority_queue<int> p; // 利润 大根堆
  5. priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> c; // 资本 小根堆
  6. for (int i = 0; i < Capital.size(); i++) {
  7. c.emplace(make_pair(Capital[i], Profits[i]));
  8. }
  9. for (int i = 0; i < k; i++) {
  10. while (!c.empty() && c.top().first <= W) {
  11. // 资本小于等于W的项目,存入利润大根堆
  12. p.emplace(c.top().second);
  13. c.pop();
  14. }
  15. if(p.empty()) break;
  16. W += p.top(); // 每次选利润最大的
  17. p.pop();
  18. }
  19. return W;
  20. }
  21. };
  22. 作者:hdye
  23. 链接:https://leetcode-cn.com/problems/ipo/solution/c-you-xian-dui-lie-by-hdye/
  24. 来源:力扣(LeetCode
  25. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

503. 下一个更大元素 II(单调栈)

单调栈是一个很重要的减少时间复杂d

  1. class Solution {
  2. public:
  3. vector<int> nextGreaterElements(vector<int>& nums) {
  4. if(nums.empty())return {
  5. };
  6. stack<int> st;
  7. nums.insert(nums.end(),nums.begin(),nums.end());
  8. st.push(-1);
  9. vector<int> res;
  10. for(int i = nums.size()-1;i>=nums.size()/2;i--)
  11. {
  12. while(!st.empty() && nums[i]>=st.top())st.pop();
  13. st.push(nums[i]);
  14. }
  15. for(int i = nums.size()/2-1;i>=0;i--)
  16. {
  17. while(!st.empty() && nums[i]>=st.top())st.pop();
  18. if(st.empty())res.push_back(-1);
  19. else res.push_back(st.top());
  20. st.push(nums[i]);
  21. }
  22. reverse(res.begin(),res.end());
  23. return res;
  24. }
  25. };
  26. class Solution {
  27. public:
  28. vector<int> nextGreaterElements(vector<int>& nums) {
  29. int len = nums.size();
  30. vector<int> vt;
  31. vector<int> res(len,-1);
  32. for(int i =0 ; i< len*2 ;i++)
  33. {
  34. while(!vt.empty()&&nums[i%len]>nums[vt.back()])
  35. {
  36. res[vt.back()]=nums[i%len];
  37. vt.pop_back();
  38. }
  39. vt.push_back(i%len);
  40. }
  41. return res;
  42. }
  43. };

506. 相对名次

依旧是使用mp转vector重写sort函数法

  1. class Solution {
  2. public:
  3. static bool func(pair<int,int>& p1, pair<int,int>& p2)
  4. {
  5. return p1.first>p2.first;
  6. }
  7. vector<string> findRelativeRanks(vector<int>& nums) {
  8. int len = nums.size();
  9. unordered_map<int,int> mp;
  10. int i=0;
  11. for(auto num:nums)mp[num]=i++;
  12. vector<pair<int,int>> order(mp.begin(),mp.end());
  13. sort( order.begin(),order.end(),func);
  14. vector<string> res(len);
  15. for(int i=0;i<len;i++)
  16. {
  17. if(i==0){
  18. res[order[i].second]="Gold Medal";}
  19. else if(i==1){
  20. res[order[i].second]="Silver Medal";}
  21. else if(i==2){
  22. res[order[i].second]="Bronze Medal";}
  23. else{
  24. res[order[i].second]=to_string(i+1);}
  25. }
  26. return res;
  27. }
  28. };

发现堆排序好像也很好用
利用堆来排序,建立一个优先队列,把分数和其坐标位置放入队列中,会自动按其分数高低排序,然后我们从顶端开始一个一个取出数据,由于保存了其在原数组的位置,我们可以直接将其存到结果res中正确的位置,用一个变量cnt来记录名词,前三名给奖牌,后面就是名次数。

  1. class Solution {
  2. public:
  3. vector<string> findRelativeRanks(vector<int>& nums) {
  4. int n = nums.size(), cnt = 1;
  5. vector<string> res(n, "");
  6. priority_queue<pair<int, int>> heap;
  7. for(int i =0; i <n; i++){
  8. heap.push({
  9. nums[i], i});
  10. }
  11. for(int i = 0; i < n; i++){
  12. int dx = heap.top().second;
  13. heap.pop();
  14. if(cnt == 1) res[dx] = "Gold Medal";
  15. else if(cnt == 2) res[dx] = "Silver Medal";
  16. else if(cnt == 3) res[dx] = "Bronze Medal";
  17. else res[dx] = to_string(cnt);
  18. cnt++;
  19. }
  20. return res;
  21. }
  22. };

507. 完美数

i从1到sqrt同时计算两个因子

  1. class Solution {
  2. public:
  3. bool checkPerfectNumber(int num) {
  4. if(num%2!=0)return false;
  5. int sum=1;
  6. int i=2;
  7. int s=ceil(sqrt(num));
  8. for(;i<s;++i)
  9. {
  10. if(num%i==0)
  11. {
  12. sum+=i+num/i;
  13. }
  14. }
  15. if(i*i==num)sum+=i;
  16. return (num==sum);
  17. }
  18. };
  19. 作者:yukarun
  20. 链接:https://leetcode-cn.com/problems/perfect-number/solution/507-wan-mei-shu-by-yukarun/
  21. 来源:力扣(LeetCode
  22. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

508. 出现次数最多的子树元素和

  1. class Solution {
  2. public:
  3. unordered_map<int, int> freqInfo;
  4. int maxFreq = 0;
  5. int dfs(TreeNode * root) {
  6. if(root != NULL) {
  7. int sum = root->val + dfs(root->left) + dfs(root->right);
  8. freqInfo[sum]++;
  9. maxFreq = std::max(maxFreq, freqInfo[sum]);
  10. return sum;
  11. } else {
  12. return 0;
  13. }
  14. }
  15. vector<int> findFrequentTreeSum(TreeNode* root) {
  16. dfs(root);
  17. vector<int> res;
  18. for(auto & kv : freqInfo) {
  19. if(kv.second == maxFreq) {
  20. res.push_back(kv.first);
  21. }
  22. }
  23. return res;
  24. }
  25. };
  26. 作者:haithink
  27. 链接:https://leetcode-cn.com/problems/most-frequent-subtree-sum/solution/er-cha-shu-de-ti-mu-yong-bian-li-de-guan-dian-jie-/
  28. 来源:力扣(LeetCode
  29. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

509. 斐波那契数(记忆化)

之前做过这道题,使用的是最直接的递归解法,但是一直不知道超时怎么优化,明白了一种东西叫记忆化把之间算过的记忆下来就可以了

  1. int fibMemo(int N, int* res) {
  2. if(N==0) return 0;
  3. if(N==1) return 1;
  4. if(res[N]==0) {
  5. res[N] = fibMemo(N-1, res) + fibMemo(N-2, res);
  6. }
  7. return res[N];
  8. }
  9. int fib(int N){
  10. /* 解法一:无优化递归,展开后存在2^N的节点,存在大量重复计算
  11. if(N==0) return 0;
  12. if(N==1) return 1;
  13. return fib(N-1) + fib(N-2);
  14. */
  15. // 解法二 , 记忆化Memo
  16. int res[N+1];
  17. for(int i=0; i < N+1; i++) {
  18. res[i] = 0;
  19. }
  20. if(N==0) return 0;
  21. if(N==1) return 1;
  22. return fibMemo(N, res);
  23. }
  24. 作者:justdoitno1
  25. 链接:https://leetcode-cn.com/problems/fibonacci-number/solution/cti-jie-dui-bi-zui-cuo-de-wu-you-hua-di-gui-memoji/
  26. 来源:力扣(LeetCode
  27. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

510. 二叉搜索树中的中序后继 II

  1. /*
  2. // Definition for a Node.
  3. class Node {
  4. public:
  5. int val;
  6. Node* left;
  7. Node* right;
  8. Node* parent;
  9. };
  10. */
  11. class Solution {
  12. public:
  13. Node* findfather(Node* node)
  14. {
  15. if(node->parent==NULL)return node;
  16. return node->parent;
  17. }
  18. Node* res;
  19. bool b = false;
  20. void dfs(Node* root,Node* node)
  21. {
  22. if(root==NULL)return;
  23. dfs(root->left,node);
  24. if(b){
  25. res = root;b=false;}
  26. if(root==node)b=true;
  27. dfs(root->right,node);
  28. }
  29. Node* inorderSuccessor(Node* node) {
  30. auto t = node;
  31. auto root = findfather(node);
  32. dfs(root,t);
  33. return res;
  34. }
  35. };

513. 找树左下角的值

  1. /**
  2. * Definition for a binary tree node.
  3. * struct TreeNode {
  4. * int val;
  5. * TreeNode *left;
  6. * TreeNode *right;
  7. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  8. * };
  9. */
  10. class Solution {
  11. public:
  12. int findBottomLeftValue(TreeNode* root) {
  13. vector<TreeNode*> cur = {
  14. root};
  15. TreeNode* res;
  16. while(!cur.empty())
  17. {
  18. vector<TreeNode*> temp;
  19. for(auto&c:cur)
  20. {
  21. if(c->left)temp.push_back(c->left);
  22. if(c->right)temp.push_back(c->right);
  23. }
  24. if(temp.empty())
  25. {
  26. return cur.front()->val;
  27. }
  28. else
  29. {
  30. cur=temp;
  31. }
  32. }
  33. return 0;
  34. }
  35. };
  36. /**
  37. * Definition for a binary tree node.
  38. * struct TreeNode {
  39. * int val;
  40. * TreeNode *left;
  41. * TreeNode *right;
  42. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  43. * };
  44. */
  45. class Solution {
  46. private:
  47. vector<int> res;
  48. public:
  49. void dfs(vector<TreeNode*> cur)
  50. {
  51. if(cur.empty())return;
  52. vector<TreeNode*> next;
  53. res.push_back(cur[0]->val);
  54. for(auto i:cur)
  55. {
  56. if(i->left)next.push_back(i->left);
  57. if(i->right)next.push_back(i->right);
  58. }
  59. dfs(next);
  60. }
  61. int findBottomLeftValue(TreeNode* root) {
  62. vector<TreeNode*> temp={
  63. root};
  64. dfs(temp);
  65. int len = res.size();
  66. return res[len-1];
  67. }
  68. };

515. 在每个树行中找最大值

  1. /**
  2. * Definition for a binary tree node.
  3. * struct TreeNode {
  4. * int val;
  5. * TreeNode *left;
  6. * TreeNode *right;
  7. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  8. * };
  9. */
  10. class Solution {
  11. public:
  12. vector<int> largestValues(TreeNode* root) {
  13. if(!root)return {
  14. };
  15. vector<int> res;
  16. vector<TreeNode*> cur = {
  17. root};
  18. res.push_back(root->val);
  19. while(!cur.empty())
  20. {
  21. vector<TreeNode*> next;
  22. int m = INT_MIN;
  23. for(int i = 0 ; i <cur.size();i++)
  24. {
  25. if(cur[i]->left)
  26. {
  27. m = max(m,cur[i]->left->val);
  28. next.push_back(cur[i]->left);
  29. }
  30. if(cur[i]->right)
  31. {
  32. m = max(m,cur[i]->right->val);
  33. next.push_back(cur[i]->right);
  34. }
  35. }
  36. if(!next.empty())res.push_back(m);
  37. cur=next;
  38. }
  39. return res;
  40. }
  41. };
  42. /**
  43. * Definition for a binary tree node.
  44. * struct TreeNode {
  45. * int val;
  46. * TreeNode *left;
  47. * TreeNode *right;
  48. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  49. * };
  50. */
  51. class Solution {
  52. private:
  53. vector<int> res;
  54. public:
  55. void dfs(vector<TreeNode*> cur)
  56. {
  57. if(cur.empty())return;
  58. int m = INT_MIN;
  59. vector<TreeNode*> next;
  60. for(auto i:cur)
  61. {
  62. m = max(m,i->val);
  63. if(i->left)next.push_back(i->left);
  64. if(i->right)next.push_back(i->right);
  65. }
  66. res.push_back(m);
  67. dfs(next);
  68. }
  69. vector<int> largestValues(TreeNode* root) {
  70. if(root==NULL)return {
  71. };
  72. vector<TreeNode*> temp={
  73. root};
  74. dfs(temp);
  75. return res;
  76. }
  77. };

516. 最长回文子序列(dp********************)

总结一下:

最长公共连续子串(大一圈正常遍历)
这个必须要记住
if(s1[i]==s2[i]) v[i][j] =v[i-1]v[j-1] +1
else v[i][j] = 0
最长回文子串
把这个字符串翻过来然后用和上面一样的方法求就行了
所有的回文子串(从右下开始遍历右上部分)
其实可以从小到大进行遍历,然后也不适用这个dp表达式,而是新写一个回文函数每次进行判断,这样实用性更广
if(s1[i]==s2[j] && ( j-i<=2 || v[i+1][j-1]) v[i][j] = true;
最长公共子序列(大一圈正常遍历)
这个必须要记住
if(s1[i]==s2[j]) v[i][j] = v[i-1][j-1]+1
else v[i][j] = max(v[i-1][j],v[i][j-1])
最长回文子序列
因为是子序列不是子串,所以可以逆置原字符串,采用最长公共子序列LCS来求解。
逆置后公共子序列就是回文子序列。

  1. class Solution {
  2. public:
  3. int longestPalindromeSubseq(string s) {
  4. int len = s.size();
  5. //vector<vector<bool>> v(len, vector<bool>(len, false));
  6. /*
  7. int max = 0 ;
  8. for(int i = len-1; i>=0 ;i--)
  9. {
  10. for(int j = i ; j <len ;j++)
  11. {
  12. if( s[i]==s[j] && (j-i<=2 || v[i+1][j-1]) )
  13. {
  14. v[i][j] = true;
  15. if(j-i+1>max)max = j -i+1;
  16. }
  17. }
  18. }
  19. return max;
  20. */
  21. string s1=s;
  22. reverse(s1.begin(),s1.end());
  23. vector<vector<int>> v(len+1, vector<int>(len+1, 0));
  24. for(int i = 1 ; i<len+1 ;i++)
  25. {
  26. for(int j = 1 ; j<len+1 ; j++)
  27. {
  28. if(s[i-1]==s1[j-1]) v[i][j] =v[i-1][j-1]+1;
  29. else v[i][j] = max(v[i-1][j],v[i][j-1]);
  30. }
  31. }
  32. return v[len][len];
  33. }
  34. };

517. 超级洗衣机

用当前值减去平均值【差值】,就是每个洗衣机要传入或者传出的数量,正数表示要传出,负数表示要传入
对于第[i]个洗衣机来说,左边要传入或者传出的数量,就是左边所有洗衣机的差值之和,为正表示左边有剩余,需要传到右边,为负表示左边不够,需要右边传过来,不管哪种情况,都要经过[i]节点,算作【流量】
差值 与 流量 的最大值,就是当前洗衣机要传入或者传出的数量
遍历所有洗衣机,找出最大值,即为最少次数

作者:beny-g
链接:https://leetcode-cn.com/problems/super-washing-machines/solution/csi-lu-by-beny-g/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  1. class Solution {
  2. public:
  3. int findMinMoves(vector<int>& machines) {
  4. int sum=0;
  5. for(int& m:machines) sum+=m;
  6. int size=machines.size();
  7. if (sum%size) return -1;
  8. int avan = sum/size;
  9. int ba=0, mx, res=0;
  10. for(int& m:machines){
  11. ba += m-avan;
  12. mx = max(m-avan, abs(ba));
  13. res = max(res, mx);
  14. };
  15. return res;
  16. }
  17. };
  18. 作者:beny-g
  19. 链接:https://leetcode-cn.com/problems/super-washing-machines/solution/csi-lu-by-beny-g/
  20. 来源:力扣(LeetCode
  21. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

518. 零钱兑换 II

set超时

  1. class Solution {
  2. public:
  3. int change(int amount, vector<int>& coins) {
  4. if(amount==0)return 1;
  5. if(coins.empty())return 0;
  6. vector<set<multiset<int>>> dp(amount+1);
  7. for(int i =1;i<=amount;i++)
  8. {
  9. for(auto&c:coins)
  10. {
  11. if(i>=c)
  12. {
  13. if(dp[i-c].empty())
  14. {
  15. if(i==c)dp[i].insert({
  16. c});
  17. }
  18. else
  19. {
  20. for(auto&j:dp[i-c])
  21. {
  22. auto t = j;
  23. t.insert(c);
  24. dp[i].insert(t);
  25. }
  26. }
  27. }
  28. }
  29. }
  30. return dp.back().size();
  31. }
  32. };

dfs超时

  1. class Solution {
  2. public:
  3. bool canPartition(vector<int>& nums) {
  4. int sum = 0;
  5. for(auto n:nums)sum+=n;
  6. if(sum%2==1)return false;
  7. //容量为sum/2,物品容量和价值都为nums
  8. int N=nums.size();
  9. vector<vector<int>> dp(N+1,vector<int>(sum/2+1,0));
  10. for(int i = 1;i<=N;i++)
  11. {
  12. for(int j =1;j<=sum/2;j++)
  13. {
  14. if(j<nums[i-1]) {
  15. dp[i][j]=dp[i-1][j];}
  16. else
  17. {
  18. dp[i][j]=max( dp[i-1][j], dp[i-1][j-nums[i-1]] + nums[i-1] );
  19. }
  20. }
  21. }
  22. return dp[N][sum/2]==sum/2;
  23. }
  24. };

dp

  1. class Solution {
  2. public:
  3. int change(int amount, vector<int>& coins) {
  4. int n = coins.size();
  5. vector<vector<int>> dp(n + 1, vector<int>(amount + 1));
  6. //base case:
  7. for(int i = 0; i <= n; i++) {
  8. dp[i][0] = 1;
  9. }
  10. for(int i = 1; i <= amount; i++) {
  11. dp[0][i] = 0;
  12. }
  13. for(int i = 1; i <= n; i++) {
  14. for(int j = 1; j <= amount; j++) {
  15. if(j - coins[i - 1] >= 0) dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]]; //完全背包,选的情况仍为i
  16. else dp[i][j] = dp[i - 1][j];
  17. }
  18. }
  19. return dp[n][amount];
  20. }
  21. };
  22. 作者:Komaeda_Nagito
  23. 链接:https://leetcode-cn.com/problems/coin-change-2/solution/dp-wan-quan-bei-bao-ji-ben-zuo-fa-c-by-kiritoh/
  24. 来源:力扣(LeetCode
  25. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

519. 随机翻转矩阵

思想还是很值得学习的,因为每次产生一个新的可能会和之前的重复,这样的话会十分耗时,一种方法是维护一个不断减少的值,每次就在小于这个值的地方产生,如果之前产生过的会用一个哈希表进行记录,逻辑上比较难理解

  1. class Solution {
  2. unordered_map<int,int> map;
  3. int m, n, num;
  4. int x, y, pos, prev;
  5. public:
  6. Solution(int n_rows, int n_cols) {
  7. m = n_rows;
  8. n = n_cols;
  9. num = m*n;
  10. }
  11. vector<int> flip() {
  12. if(num == 0) return {
  13. };
  14. pos = rand()%(num);
  15. num--;//下一轮,减少一个数
  16. if(map.count(pos))//map包含pos的key
  17. {
  18. prev = pos;//记录当前pos
  19. pos = map[pos];//真实的取走的pos
  20. if(!map.count(num))//把最后一个位置的数换到当前
  21. map[prev] = num;
  22. else//如果最后一个位置有map值,用其值替换
  23. map[prev] = map[num];
  24. }
  25. else//map不包含pos的key
  26. {
  27. //pos就是当前位置,只需把末尾的数替换到当前,同上
  28. if(!map.count(num))
  29. map[pos] = num;
  30. else
  31. map[pos] = map[num];
  32. }
  33. x = pos/n;
  34. y = pos-x*n;
  35. return {
  36. x, y};
  37. }
  38. void reset() {
  39. num = m*n;
  40. map.clear();
  41. }
  42. };
  43. 作者:kobe24o
  44. 链接:https://leetcode-cn.com/problems/random-flip-matrix/solution/zhuan-cheng-1wei-suo-xiao-chang-du-ha-xi-mapti-hua/
  45. 来源:力扣(LeetCode
  46. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

520. 检测大写字母

  1. class Solution {
  2. public:
  3. bool detectCapitalUse(string word) {
  4. if(word.empty() || word.size()==1)return true;
  5. bool b0 = (word[0]>='a' && word[0]<='z');
  6. bool b1 = (word[1]>='a' && word[1]<='z');
  7. if(word.size()==2 && b0 && !b1)return false;
  8. for(int i = 2;i<word.size();i++)
  9. {
  10. if( (b0 && !b1) || ((word[i]>='a' && word[i]<='z')!=b1))return false;
  11. }
  12. return true;
  13. }
  14. };

523. 连续的子数组和

这道题不适合dfs的,因为是子数组这种的直接用dp就可以了,一般子序列用dfs

  1. class Solution {
  2. public:
  3. bool checkSubarraySum(vector<int>& nums, int k) {
  4. k=abs(k);
  5. int len = nums.size();
  6. vector<int> dp = nums;
  7. for(int i = 1;i<len;i++)
  8. {
  9. dp[i]=dp[i-1]+dp[i];
  10. }
  11. int sum=dp.back();
  12. unordered_set<int> st;
  13. if(k==0)
  14. {
  15. for(int i = 0;i<len;i++)
  16. {
  17. for(int j = i+1;j<len;j++)
  18. {
  19. if (i == 0) {
  20. if (dp[j]==0)return true; }
  21. else if ((dp[j]-dp[i-1])==0)return true;
  22. }
  23. }
  24. }
  25. else
  26. {
  27. for(int i = 0;i<len;i++)
  28. {
  29. for(int j = i+1;j<len;j++)
  30. {
  31. if (i == 0) {
  32. if (dp[j]%k==0)return true; }
  33. else if ((dp[j]-dp[i-1])%k==0)return true;
  34. }
  35. }
  36. }
  37. return false;;
  38. }
  39. };

524. 通过删除字母匹配到字典里最长单词

dp二维,超时了

  1. class Solution {
  2. public:
  3. bool isok(string a, string b)
  4. {
  5. int lena = a.size();
  6. int lenb = b.size();
  7. vector<vector<int>> dp(lena + 1, vector<int>(lenb + 1, false));
  8. for (int j = 0; j <= lenb; j++)
  9. {
  10. dp[0][j] = true;
  11. }
  12. for (int i = 1; i <= lena; i++)
  13. {
  14. for (int j = 1; j <= lenb; j++)
  15. {
  16. if (a[i - 1] == b[j - 1])
  17. {
  18. dp[i][j] = dp[i - 1][j - 1] || dp[i][j - 1];
  19. }
  20. else
  21. {
  22. dp[i][j] = dp[i][j - 1];
  23. }
  24. }
  25. }
  26. return dp[lena][lenb];
  27. }
  28. string findLongestWord(string s, vector<string>& d) {
  29. vector<string> res;
  30. int ml= 0;
  31. for(auto&d1:d)
  32. {
  33. if(isok(d1,s))
  34. {
  35. if(d1.size()>ml)
  36. {
  37. ml=d1.size();
  38. res.clear();
  39. res.push_back(d1);
  40. }
  41. else if(d1.size()==ml)
  42. {
  43. res.push_back(d1);
  44. }
  45. }
  46. }
  47. if(res.empty())return "";
  48. sort(res.begin(),res.end());
  49. return res.front();
  50. }
  51. };

双指针一遍遍历的方法高效很多

  1. class Solution {
  2. public:
  3. bool isok(string a, string b)
  4. {
  5. int lena = a.size();
  6. int lenb = b.size();
  7. int i = 0,j=0;
  8. while(j<lenb)
  9. {
  10. if(a[i]==b[j])
  11. {
  12. i++;j++;
  13. }
  14. else j++;
  15. }
  16. return i==lena;
  17. }
  18. string findLongestWord(string s, vector<string>& d) {
  19. vector<string> res;
  20. int ml= 0;
  21. for(auto&d1:d)
  22. {
  23. if(isok(d1,s))
  24. {
  25. if(d1.size()>ml)
  26. {
  27. ml=d1.size();
  28. res.clear();
  29. res.push_back(d1);
  30. }
  31. else if(d1.size()==ml)
  32. {
  33. res.push_back(d1);
  34. }
  35. }
  36. }
  37. if(res.empty())return "";
  38. sort(res.begin(),res.end());
  39. return res.front();
  40. }
  41. };

525. 连续数组

  1. class Solution {
  2. public:
  3. int findMaxLength(vector<int> nums) {
  4. if(nums.empty())return 0;
  5. int len = nums.size();
  6. vector<int> dp(len, 0);
  7. unordered_map<int,int> mp;
  8. mp[0]=-1;
  9. dp[0] = (nums[0] == 0 ? -1 : 1);
  10. mp[dp[0]]=0;
  11. int res = 0;
  12. for (int i = 1; i < len; i++)
  13. {
  14. dp[i] = dp[i - 1] + (nums[i] == 0 ? -1 : 1);
  15. if(mp.find(dp[i])==mp.end())
  16. {
  17. mp[dp[i]]=i;
  18. }
  19. else
  20. {
  21. res = max(res,i-mp[dp[i]]);
  22. }
  23. }
  24. return res;
  25. }
  26. };
  27. class Solution {
  28. public:
  29. int findMaxLength(vector<int>& nums) {
  30. unordered_map<int,int> mp;
  31. mp[0]=-1;
  32. int sum=0;
  33. int res=0;
  34. for(int i = 0 ;i<nums.size() ;i++)
  35. {
  36. int num =nums[i];
  37. sum += (num==0)?-1:1;
  38. if(mp.find(sum)==mp.end())
  39. {
  40. mp[sum]=i;}
  41. else
  42. {
  43. res = max(res, i-mp[sum]);}
  44. }
  45. return res;
  46. }
  47. };

526. 优美的排列

  1. class Solution {
  2. public:
  3. int res =0;
  4. vector<int> path;
  5. vector<int> visited;
  6. void dfs(int N,int p)
  7. {
  8. if(path.size()==N)
  9. {
  10. res++;
  11. return;
  12. }
  13. for(int i = 1;i<=N;i++)
  14. {
  15. if(visited[i-1]==0 && (i%p==0 || p%i==0))
  16. {
  17. visited[i-1]=1;
  18. path.push_back(i);
  19. dfs(N,p+1);
  20. path.pop_back();
  21. visited[i-1]=0;
  22. }
  23. }
  24. }
  25. int countArrangement(int N) {
  26. visited = vector<int>(N, 0);
  27. dfs(N,1);
  28. return res;
  29. }
  30. };

528. 按权重随机选择

  1. class Solution {
  2. public:
  3. vector<int> dp;
  4. int sum;
  5. Solution(vector<int>& w) {
  6. dp=w;
  7. for(int i = 1;i<dp.size();i++)
  8. {
  9. dp[i]=dp[i-1]+dp[i];
  10. }
  11. sum=dp.back();
  12. }
  13. int pickIndex() {
  14. int t = rand()%sum;
  15. int x= lower_bound(dp.begin(),dp.end(),t) - dp.begin();
  16. return x;
  17. }
  18. };
  19. /**
  20. * Your Solution object will be instantiated and called as such:
  21. * Solution* obj = new Solution(w);
  22. * int param_1 = obj->pickIndex();
  23. */

530. 二叉搜索树的最小绝对差

  1. /**
  2. * Definition for a binary tree node.
  3. * struct TreeNode {
  4. * int val;
  5. * TreeNode *left;
  6. * TreeNode *right;
  7. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  8. * };
  9. */
  10. class Solution {
  11. public:
  12. int res = INT_MAX;
  13. int pre =-1;
  14. void dfs(TreeNode* root)
  15. {
  16. if(!root)return;
  17. dfs(root->left);
  18. if(pre==-1)
  19. {
  20. pre = root->val;
  21. }
  22. else
  23. {
  24. res = min(res,abs(root->val-pre));
  25. pre = root->val;
  26. }
  27. dfs(root->right);
  28. }
  29. int getMinimumDifference(TreeNode* root) {
  30. dfs(root);
  31. return res;
  32. }
  33. };

531. 孤独像素 I

  1. class Solution {
  2. public:
  3. int findLonelyPixel(vector<vector<char>>& picture) {
  4. int m = picture.size();
  5. int n = picture[0].size();
  6. vector<int> dp1(m,0);
  7. vector<int> dp2(n,0);
  8. for(int i = 0;i<m;i++)
  9. {
  10. for(int j = 0;j<n;j++)
  11. {
  12. if(picture[i][j]=='B')
  13. {
  14. dp1[i]++;
  15. dp2[j]++;
  16. }
  17. }
  18. }
  19. int res = 0;
  20. for(int i=0;i<m;i++)
  21. {
  22. for(int j =0;j<n;j++)
  23. {
  24. if(picture[i][j]=='B' && dp1[i]==1 && dp2[j]==1)
  25. {
  26. res++;
  27. }
  28. }
  29. }
  30. return res;
  31. }
  32. };

532. 数组中的K-diff数对

  1. class Solution {
  2. public:
  3. int findPairs(vector<int>& nums, int k) {
  4. if(k<0)return 0;
  5. unordered_map<int,int> mp;
  6. for(auto&n:nums)mp[n]++;
  7. int res =0;
  8. if(k==0)
  9. {
  10. for(auto&m:mp)
  11. {
  12. if(m.second>1)res++;
  13. }
  14. return res;
  15. }
  16. for(auto&m:mp)
  17. {
  18. if(mp.find(m.first+k)!=mp.end())res++;
  19. }
  20. return res;
  21. }
  22. };

536. 从字符串生成二叉树

思路:使用栈,如果是数字就放入栈中,如果是)ji

  1. /**
  2. * Definition for a binary tree node.
  3. * struct TreeNode {
  4. * int val;
  5. * TreeNode *left;
  6. * TreeNode *right;
  7. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  8. * };
  9. */
  10. class Solution {
  11. public:
  12. TreeNode* str2tree(string s) {
  13. vector<string> vt;
  14. int i = 0;
  15. while(i<s.size())
  16. {
  17. if (s[i] == '(') {
  18. vt.push_back("("); i++;
  19. }
  20. else if (s[i] == ')') {
  21. vt.push_back(")"); i++;
  22. }
  23. else
  24. {
  25. int j = i;
  26. while(i<s.size() && isdigit(s[i]))i++;
  27. vt.push_back(s.substr(j,i-j));
  28. }
  29. }
  30. stack<TreeNode*> st;
  31. for(int i = 0;i<vt.size();i++)
  32. {
  33. if(vt[i]==")")
  34. {
  35. auto t = st.top();st.pop();
  36. if(!st.top()->left)st.top()->left=t;
  37. else st.top()->right=t;
  38. }
  39. else if(vt[i]=="("){
  40. }
  41. else
  42. {
  43. TreeNode* t = new TreeNode(stoi(vt[i]));
  44. st.push(t);
  45. }
  46. }
  47. while(st.size()>1 )st.pop();
  48. return st.top();
  49. }
  50. };

538. 把二叉搜索树转换为累加树

先右再左就是中序遍历的倒序了,然后采用累加的手段累加到前面的节点上

  1. BST的中序遍历就是从小到大,那么反过来就是从大到小,然后累加就好了.
  2. class Solution {
  3. int num = 0;
  4. public TreeNode convertBST(TreeNode root) {
  5. if (root != null) {
  6. //遍历右子树
  7. convertBST(root.right);
  8. //遍历顶点
  9. root.val = root.val + num;
  10. num = root.val;
  11. //遍历左子树
  12. convertBST(root.left);
  13. return root;
  14. }
  15. return null;
  16. }
  17. }

539. 最小时间差(先排序)

使用了两层循环,没有先排序,是n方的复杂度

  1. class Solution {
  2. public:
  3. vector<int> func(string s)
  4. {
  5. int h,m;
  6. int i = 0;
  7. while(i<s.size())
  8. {
  9. int j = i;
  10. while(i<s.size() && s[i]!=':')i++;
  11. if(s[i]==':')
  12. {
  13. h = stoi(s.substr(j,i-j));
  14. i++;
  15. }
  16. else
  17. {
  18. m = stoi(s.substr(j,i-j));break;
  19. }
  20. }
  21. return {
  22. h,m};
  23. }
  24. int func1(vector<int> a,vector<int> b)
  25. {
  26. if(b[0]>=a[0])swap(a,b);
  27. return min((23 - a[0]) * 60 + (60 - a[1]) + b[0] * 60 + b[1], (a[0]==b[0])?(abs(a[1]-b[1])):((a[0] - b[0]-1) * 60 + a[1] + (60 - b[1])) );
  28. }
  29. int findMinDifference(vector<string>& timePoints) {
  30. vector<vector<int>> vt;
  31. for(auto&t:timePoints)
  32. {
  33. auto r = func(t);
  34. vt.push_back({
  35. r[0],r[1]});
  36. }
  37. int res = INT_MAX;
  38. for(int i = 0;i<vt.size();i++)
  39. {
  40. for(int j = 0;j<i;j++)
  41. {
  42. res = min(res,func1(vt[i],vt[j]));
  43. }
  44. }
  45. return res;
  46. }
  47. };

先排序之后,在遍历比较,时间复杂度为nlogn,先排序是减少时复杂度比较重要的技巧

  1. class Solution {
  2. public:
  3. vector<int> func(string s)
  4. {
  5. int h,m;
  6. int i = 0;
  7. while(i<s.size())
  8. {
  9. int j = i;
  10. while(i<s.size() && s[i]!=':')i++;
  11. if(s[i]==':')
  12. {
  13. h = stoi(s.substr(j,i-j));
  14. i++;
  15. }
  16. else
  17. {
  18. m = stoi(s.substr(j,i-j));break;
  19. }
  20. }
  21. return {
  22. h,m};
  23. }
  24. int func1(vector<int> a,vector<int> b)
  25. {
  26. if(b[0]>=a[0])swap(a,b);
  27. return min((23 - a[0]) * 60 + (60 - a[1]) + b[0] * 60 + b[1], (a[0]==b[0])?(abs(a[1]-b[1])):((a[0] - b[0]-1) * 60 + a[1] + (60 - b[1])) );
  28. }
  29. static bool cmp(vector<int>a,vector<int>b)
  30. {
  31. if(a[0]==b[0])return a[1]<b[1];
  32. return a[0]<b[0];
  33. }
  34. int findMinDifference(vector<string>& timePoints) {
  35. vector<vector<int>> vt;
  36. for(auto&t:timePoints)
  37. {
  38. auto r = func(t);
  39. vt.push_back({
  40. r[0],r[1]});
  41. }
  42. int res = INT_MAX;
  43. sort(vt.begin(),vt.end(),cmp);
  44. for(int i = 0;i<vt.size()-1;i++)
  45. {
  46. res = min(res,func1(vt[i],vt[i+1]));
  47. }
  48. res = min(res,func1(vt[0],vt.back()));
  49. return res;
  50. }
  51. };

542. 01 矩阵(dfs,bfs)

dfs超时,推荐dfs

  1. class Solution {
  2. public:
  3. //dfs的时间复杂度高,当dfs复杂度高用bfs空间复杂度高的试试
  4. vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
  5. int len1 = matrix.size();
  6. int len2 = matrix[0].size();
  7. vector<vector<int>> board(len1,vector<int>(len2,0));
  8. vector<vector<int>> visited(len1,vector<int>(len2,0));//访问数组
  9. queue<vector<int>> qt;
  10. for(int i = 0;i<len1;i++)
  11. {
  12. for(int j =0;j<len2;j++)
  13. {
  14. if(matrix[i][j]==0){
  15. vector<int> t;t.push_back(i);t.push_back(j);visited[i][j]=1;qt.push(t);}
  16. }
  17. }
  18. int num = 1;
  19. while(!qt.empty())
  20. {
  21. int len = qt.size();
  22. for(int c = 0;c<len;c++)
  23. {
  24. auto temp = qt.front();qt.pop();
  25. int i = temp[0],j = temp[1];
  26. if(i-1>=0 && visited[i-1][j]==0){
  27. board[i-1][j]=num; qt.push({
  28. i-1,j});visited[i-1][j]=1;}
  29. if(j-1>=0 && visited[i][j-1]==0){
  30. board[i][j-1]=num; qt.push({
  31. i,j-1});visited[i][j-1]=1;}
  32. if(i+1<len1 && visited[i+1][j]==0){
  33. board[i+1][j]=num; qt.push({
  34. i+1,j});visited[i+1][j]=1;}
  35. if(j+1<len2 && visited[i][j+1]==0){
  36. board[i][j+1]=num; qt.push({
  37. i,j+1});visited[i][j+1]=1;}
  38. }
  39. num++;
  40. }
  41. return board;
  42. }
  43. };

在应用题中的dfs经常会遇到一个问题,在查看这个点四周的状态时,下一次递归又会回到这个地方,容易造成无限循环,在这道题中,可以使用不传入引用值,将已经搜索过的数改为其他数的情况,但这种方法并不万能
这里面值得推荐的一个地方时,利用递归的次数来作为要返回的数量

  1. class Solution {
  2. private:
  3. int m;
  4. int n;
  5. public:
  6. int dfs(int i, int j, vector<vector<int>> matrix)
  7. {
  8. if (i < 0 || i >= m || j < 0 || j >= n) return 20000;
  9. if (matrix[i][j] == 0)return 0;
  10. if (matrix[i][j] == 'A')return 20000;
  11. matrix[i][j] = 'A';
  12. int num1 = min(dfs(i - 1, j, matrix),dfs(i+1,j,matrix));
  13. int num2 = min(dfs(i, j + 1, matrix), dfs(i, j - 1, matrix));
  14. return min(num1,num2)+1;
  15. }
  16. vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
  17. if (matrix.empty()) return matrix;
  18. m = matrix.size();
  19. n = matrix[0].size();
  20. for (int i = 0; i < m; i++)
  21. {
  22. for (int j = 0; j < n; j++)
  23. {
  24. matrix[i][j] = dfs(i, j, matrix);
  25. }
  26. }
  27. return matrix;
  28. }
  29. };

动态规划方法,对于有些问题,很好找到其与旁边的对应关系
解题思路
定义dp[i][j]表示该位置距离0的最短距离,其实很容易想到dp[i][j]要么等于0,要么等于min(dp[i-1][j],dp[i+1][j],dp[i][j-1],dp[i][j+1])+1

这个问题棘手的就是,我们更新状态的时候,要么从左上到右下,要么右下到左上,或者更不常见的右上到左下以及左下到右上。无论哪种更新方式都只能依赖两个前置状态(比如从左上到右下时, dp[i][j]只能依赖dp[i-1][j]和dp[i][j-1])。

这里做两遍dp状态的更新来解决上述问题, 第一次从左上到右下,转移方程为:
dp[i][j] = 0 或
dp[i][j] = min(dp[i][j-1]+1, dp[i-1][j]+1)
第二次更新从右下到左上,转移方程为
dp[i][j] = 0 或
dp[i][j] = min(dp[i][j], dp[i][j+1]+1, dp[i+1][j]+1)

齐活

作者:yuexiwen
链接:https://leetcode-cn.com/problems/01-matrix/solution/c-2bian-dp-jian-dan-yi-dong-by-yuexiwen/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  1. class Solution {
  2. public:
  3. vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
  4. vector<vector<int>> dp(matrix.size(), vector<int>(matrix[0].size(), 0));
  5. for (int i = 0; i < matrix.size(); ++i) {
  6. for (int j = 0; j < matrix[0].size(); ++j) {
  7. if (!matrix[i][j]) continue;
  8. int t_val = i == 0 ? 10001 : dp[i-1][j] + 1;
  9. int l_val = j == 0 ? 10001 : dp[i][j-1] + 1;
  10. dp[i][j] = min(t_val, l_val);
  11. }
  12. }
  13. for (int i = matrix.size()-1; i >= 0; --i) {
  14. for (int j = matrix[0].size()-1; j >= 0; --j) {
  15. if (!matrix[i][j]) continue;
  16. int b_val = i == matrix.size()-1 ? 10001 : dp[i+1][j] + 1;
  17. int r_val = j == matrix[0].size()-1 ? 10001 : dp[i][j+1] +1;
  18. dp[i][j] = min(dp[i][j], min(b_val, r_val));
  19. }
  20. }
  21. return dp;
  22. }
  23. };
  24. 作者:yuexiwen
  25. 链接:https://leetcode-cn.com/problems/01-matrix/solution/c-2bian-dp-jian-dan-yi-dong-by-yuexiwen/
  26. 来源:力扣(LeetCode
  27. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

543. 二叉树的直径

只要对每一个结点求出其左右子树深度之和,这个值作为一个候选值,然后再对左右子结点分别调用求直径对递归函数,这三个值相互比较,取最大的值更新结果res,因为直径不一定会经过根结点,所以才要对左右子结点再分别算一次。

  1. /**
  2. * Definition for a binary tree node.
  3. * struct TreeNode {
  4. * int val;
  5. * TreeNode *left;
  6. * TreeNode *right;
  7. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  8. * };
  9. */
  10. class Solution {
  11. private:
  12. int res = 0;
  13. public:
  14. int maxDepth(TreeNode* root)
  15. {
  16. if(root==NULL)return 0;
  17. return max( maxDepth( root->left),maxDepth( root->right) )+1;
  18. }
  19. void maxValue(TreeNode* root)
  20. {
  21. if(root==NULL)return;
  22. res = max(res, maxDepth(root->left)+maxDepth(root->right) );
  23. maxValue(root->left);
  24. maxValue(root->right);
  25. }
  26. int diameterOfBinaryTree(TreeNode* root) {
  27. maxValue(root);
  28. return res;
  29. }
  30. };

547. 朋友圈(并查集)

并查集 https://blog.csdn.net/zjy\_code/article/details/80634149

  1. 初始化:初始的时候每个结点各自为一个集合,father[i]表示结点 i 的父亲结点,如果 father[i]=i,我们认为这个结点是当前集合根结点。

    void init() {

    1. for (int i = 1; i <= n; ++i) {
    2. father[i] = i;
    3. }

    }

  2. 查找:查找结点所在集合的根结点,结点 x 的根结点必然也是其父亲结点的根结点。

    int get(int x) {

    1. if (father[x] == x) {
    2. // x 结点就是根结点
    3. return x;
    4. }
    5. return get(father[x]); // 返回父结点的根结点

    }

  3. 合并:将两个元素所在的集合合并在一起,通常来说,合并之前先判断两个元素是否属于同一集合。

    void merge(int x, int y) {

    1. x = get(x);
    2. y = get(y);
    3. if (x != y) {
    4. // 不在同一个集合
    5. father[y] = x;
    6. }

    }

路径压缩

  1. int get(int x) {
  2. if (father[x] == x) {
  3. // x 结点就是根结点
  4. return x;
  5. }
  6. return father[x] = get(father[x]); // 返回父结点的根结点,并另当前结点父结点直接为根结点
  7. }

————————————————
版权声明:本文为CSDN博主「zjy_code」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zjy\_code/article/details/80634149
不管是大侠问题还是朋友圈问题,这类问题都用并查集模板来实现,本来想维护一个set,但是很容易陷到无限循环的陷阱中
并查集模板

  1. struct DSU
  2. {
  3. std::vector<int> data;
  4. void init(int n) {
  5. data.assign(n, -1); }
  6. bool unionSet(int x, int y)
  7. {
  8. x = root(x);
  9. y = root(y);
  10. if (x != y)
  11. {
  12. if (data[y] < data[x])
  13. {
  14. std::swap(x, y);
  15. }
  16. data[x] += data[y];
  17. data[y] = x;
  18. }
  19. return x != y;
  20. }
  21. bool same(int x, int y) {
  22. return root(x) == root(y); }
  23. int root(int x) {
  24. return data[x] < 0 ? x : data[x] = root(data[x]); }
  25. int size(int x) {
  26. return -data[root(x)]; }
  27. };
  28. class Solution {
  29. public:
  30. int findCircleNum(vector<vector<int>>& M)
  31. {
  32. int ans = M.size();
  33. DSU dsu;
  34. dsu.init(M.size());
  35. for (size_t i = 0; i < M.size(); i++)
  36. {
  37. for (size_t j = i + 1; j < M.size(); j++)
  38. {
  39. if (M[i][j] == 0) continue;
  40. ans -= dsu.unionSet(i, j);
  41. }
  42. }
  43. return ans;
  44. }
  45. };
  46. 作者:ikaruga
  47. 链接:https://leetcode-cn.com/problems/friend-circles/solution/547-by-ikaruga/
  48. 来源:力扣(LeetCode
  49. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  50. 作者:ikaruga
  51. 链接:https://leetcode-cn.com/problems/friend-circles/solution/547-by-ikaruga/
  52. 来源:力扣(LeetCode
  53. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

很好的解答

  1. /*
  2. 参考思想如下:https://blog.csdn.net/qq_41593380/article/details/81146850
  3. 参考了两份C++实现,改进以后形成以下代码
  4. */
  5. class Solution {
  6. public:
  7. int father[210];
  8. //查找祖先节点,当节点记录的祖先是自己,则表示查找到祖先了
  9. int findFather(int x)
  10. {
  11. while(x!=father[x])
  12. {
  13. x = father[x];
  14. }
  15. return x;
  16. }
  17. //合并节点:设置共同祖先
  18. void Union(int a,int b)
  19. {
  20. int fa = findFather(a);
  21. int fb = findFather(b);
  22. if(fa!=fb)
  23. {
  24. father[fa] = fb;
  25. }
  26. }
  27. //最开始的时候,每个节点时分散的,都是自己的祖先
  28. void init()
  29. {
  30. for(int i=0;i<210;i++)
  31. {
  32. father[i] = i;
  33. }
  34. }
  35. //主函数
  36. int findCircleNum(vector<vector<int>>& M) {
  37. init();
  38. //对N个学生两两做判断
  39. for(int i=0;i<M.size();i++)
  40. {
  41. for(int j=i+1;j<M.size();j++) //只遍历少半个矩阵
  42. {
  43. if(M[i][j]==1)
  44. {
  45. Union(i,j); //对有关系的进行合并,使其为同一个父节点
  46. }
  47. }
  48. }
  49. //一次遍历找到所有祖先节点,即为朋友圈的个数
  50. int res = 0;
  51. for(int i=0;i<M.size();i++)
  52. {
  53. if(i==father[i])
  54. {
  55. res++;
  56. }
  57. }
  58. return res;
  59. }
  60. };
  61. 作者:zhang-zhe
  62. 链接:https://leetcode-cn.com/problems/friend-circles/solution/c-bing-cha-ji-shi-xian-by-zhang-zhe/
  63. 来源:力扣(LeetCode
  64. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

560. 和为K的子数组

这道题用哈希实现是太简单了,用新的数组不仅复杂还容易出错。不要用数组去储存前n项和,而是储存在哈希表里,因为这样还能保存次数。虽然子串要求顺序,,但是这和就是连续求的并不影响。
用一个哈希表来建立连续子数组之和跟其出现次数之间的映射,初始化要加入{0,1}这对映射,这是为啥呢,因为我们的解题思路是遍历数组中的数字,用sum来记录到当前位置的累加和,我们建立哈希表的目的是为了让我们可以快速的查找sum-k是否存在,即是否有连续子数组的和为sum-k,如果存在的话,那么和为k的子数组一定也存在,这样当sum刚好为k的时候,那么数组从起始到当前位置的这段子数组的和就是k,满足题意,如果哈希表中事先没有m[0]项的话,这个符合题意的结果就无法累加到结果res中,这就是初始化的用途。
————————————————
版权声明:本文为CSDN博主「pushup8」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/pushup8/article/details/85341207

  1. class Solution {
  2. public:
  3. int subarraySum(vector<int>& nums, int k) {
  4. int sum = 0, ans = 0;
  5. unordered_map<int,int> mp;
  6. mp[0] = 1;
  7. for(int i: nums){
  8. sum += i;
  9. if(mp.find(sum-k) != mp.end()) ans += mp[sum-k];
  10. mp[sum] ++;
  11. }
  12. return ans;
  13. }
  14. };
  15. 作者:jarvis1890
  16. 链接:https://leetcode-cn.com/problems/subarray-sum-equals-k/solution/qian-zhui-he-shi-xian-jian-dan-by-jarvis1890/
  17. 来源:力扣(LeetCode
  18. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

564. 寻找最近的回文数

如果数组的字符串长度 == 1,数字n - 1
开头为1,99为一个候选答案 例:100000,答案为99999
开头为9, 10
01为一个候选答案 例:99999,答案为100001
如果本身对称,则把最中间的一个(或两个)位数减(如果0则加)一
例:123321,答案为122221
例:120021,答案为121121
如果不对称:
把前半部分逆序替换掉后半部分 例:1223,答案为1221
把最中间的一个(或两个)位数加一 例:1283,答案为1331,而非1221
把最中间的一个(或两个)位数减一 例:1800,答案为1771,而非1881

567. 字符串的排列

  1. class Solution {
  2. public:
  3. bool checkInclusion(string s1, string s2) {
  4. unordered_map<char,int> mp1,window;
  5. for(auto s:s1)mp1[s]++;
  6. for(int i = 0;i< s2.size() ;i++)
  7. {
  8. if(i<s1.size())
  9. {
  10. window[s2[i]]++;}
  11. else
  12. {
  13. window[s2[i]]++;
  14. if(window[s2[i-s1.size()]]>1)
  15. {
  16. window[s2[i-s1.size()]]--;}
  17. else window.erase(s2[i-s1.size()]);
  18. }
  19. if(window==mp1)return true;
  20. }
  21. return false;
  22. }
  23. };

572. 另一个树的子树

里面有两个值得注意的地方,一个是使用||优化单个节点位空的情况,一个是主递归里必须判断s是否为0,虽然到负递归里不会出错,但是主递归里涉及到了s的子节点所以必须判断

  1. /**
  2. * Definition for a binary tree node.
  3. * struct TreeNode {
  4. * int val;
  5. * TreeNode *left;
  6. * TreeNode *right;
  7. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  8. * };
  9. */
  10. class Solution {
  11. public:
  12. bool isequal(TreeNode* root1,TreeNode* root2)
  13. {
  14. if(root1==NULL && root2==NULL)return true;
  15. //if(root1!= NULL && root2==NULL)return false;
  16. //if(root1==NULL && root2!=NULL)return false;
  17. if(root1==NULL || root2==NULL)return false;
  18. if(root1->val != root2->val)return false;
  19. return isequal(root1->left,root2->left) && isequal(root1->right,root2->right);
  20. }
  21. bool isSubtree(TreeNode* s, TreeNode* t) {
  22. if(s==NULL)return false;
  23. if( isequal(s,t)==true )return true;
  24. return isSubtree(s->left,t) || isSubtree(s->right,t);
  25. }
  26. };

576. 出界的路径数

超时,但是道理时正确的

  1. class Solution {
  2. int res;
  3. public:
  4. void dfs(int m, int n, int N,vector<vector<int>> M, int i, int j,int num)
  5. {
  6. if(num>N)return;//当步数已经大于N就失效了
  7. if( (i<0 || i>=m || j<0 || j>= n) && num<=N ) {
  8. res++;return;}//到达边界而且满足要求的
  9. dfs(m,n,N,M,i+1,j,num+1);
  10. dfs(m,n,N,M,i-1,j,num+1);
  11. dfs(m,n,N,M,i,j+1,num+1);
  12. dfs(m,n,N,M,i,j-1,num+1);
  13. }
  14. int findPaths(int m, int n, int N, int i, int j) {
  15. vector<vector<int>> M(m, vector<int>(n,1));
  16. int num=0;
  17. dfs(m,n,N,M,i,j,num);
  18. return res;
  19. }
  20. };

583. 两个字符串的删除操作

  1. class Solution {
  2. public:
  3. int minDistance(string word1, string word2) {
  4. int len1 = word1.size();
  5. int len2 = word2.size();
  6. vector<vector<int>> dp(len1+1,vector<int>(len2+1,0));
  7. for(int i =1 ;i<=len1 ;i++)
  8. {
  9. for(int j =1 ;j <=len2 ;j++)
  10. {
  11. if(word1[i-1]==word2[j-1])
  12. {
  13. dp[i][j] = dp[i-1][j-1] + 1;}
  14. else
  15. {
  16. dp[i][j] = max(dp[i-1][j],dp[i][j-1]);}
  17. }
  18. }
  19. return len1+len2-2*dp[len1][len2];
  20. }
  21. };

594. 最长和谐子序列(哈希)

  1. class Solution {
  2. public:
  3. int findLHS(vector<int>& nums) {
  4. unordered_map<int,int> mp;
  5. for(auto num:nums)
  6. {
  7. if(mp.find(num)!=mp.end())mp[num]++;
  8. else mp[num]=1;
  9. }
  10. int res=0;
  11. set<int> st(nums.begin(),nums.end());
  12. for(auto num:st)
  13. {
  14. if(mp.find(num-1)!=mp.end())
  15. {
  16. res = max(res,mp[num]+mp[num-1]);}
  17. if(mp.find(num+1)!=mp.end())
  18. {
  19. res= max(res, mp[num]+mp[num+1]);}
  20. }
  21. return res;
  22. }
  23. };

发表评论

表情:
评论列表 (有 0 条评论,96人围观)

还没有评论,来说两句吧...

相关阅读