leetcode解题思路分析(七十八)686 - 692 题

雨点打透心脏的1/2处 2022-10-05 01:59 253阅读 0赞
  1. 重复叠加字符串匹配
    给定两个字符串 a 和 b,寻找重复叠加字符串 a 的最小次数,使得字符串 b 成为叠加后的字符串 a 的子串,如果不存在则返回 -1。

指针滑动b,循环检测a即可,如果找不到则返回-1

  1. class Solution {
  2. public:
  3. static const int N = 10010;
  4. int ne[N + 1];
  5. int repeatedStringMatch(string a, string b) {
  6. int n = b.size();
  7. int m = a.size();
  8. b = " " + b;
  9. // next数组
  10. for (int i = 2, j = 0; i <= n ; i ++ ) {
  11. while (j && b[i] != b[j + 1]) j = ne[j];
  12. if (b[i] == b[j + 1]) j ++ ;
  13. ne[i] = j;
  14. }
  15. int i = 0, j = 0;
  16. // 终止条件
  17. while(i - j < m) {
  18. while (j && b[j + 1] != a[i % m]) j = ne[j];
  19. if (a[i % m] == b[j + 1]) j ++ ;
  20. i ++ ;
  21. if (j == n) break;
  22. }
  23. if (j == n) {
  24. return (i % m == 0) ? i / m : i / m + 1;
  25. }
  26. else return - 1;
  27. }
  28. };
  1. 最长同值路径
    给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。

DFS递归即可

  1. /** * 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) {} * }; */
  2. class Solution {
  3. private:
  4. // 记录最大的同值路径(边数)
  5. int res = 0;
  6. int dfs(TreeNode* curr)
  7. {
  8. if (curr == nullptr)
  9. {
  10. return 0;
  11. }
  12. // 计算从自己开始最大值
  13. int left = 0;
  14. int right = 0;
  15. // 计算当前左右子节点最大值
  16. int leftLongest = dfs(curr->left);
  17. int rightLongest = dfs(curr->right);
  18. // 判断是否相等来决定是否要更新自己最大值
  19. if (curr->left != nullptr && curr->val == curr->left->val)
  20. {
  21. left += leftLongest + 1;
  22. }
  23. if (curr->right != nullptr && curr->val == curr->right->val)
  24. {
  25. right += rightLongest + 1;
  26. }
  27. // 比较获取最大值
  28. res = max(res, left+right);
  29. // 返回时候是取一边最大值,从而和父节点构建更大的同值路径
  30. return max(left, right);
  31. }
  32. public:
  33. int longestUnivaluePath(TreeNode* root) {
  34. dfs(root);
  35. return res;
  36. }
  37. };
  1. ”马“在棋盘上的概率
    “马” 每一步都从可选的位置(包括棋盘外部的)中独立随机地选择一个进行移动,直到移动了 K 次或跳到了棋盘外面。求移动结束后,“马” 仍留在棋盘上的概率。

dp得解

  1. const int dx[8]={ -1,-2,-2,-1, 1, 2, 2,1};
  2. const int dy[8]={ 2, 1,-1,-2,-2,-1, 1,2};
  3. double d[105][30][30];
  4. class Solution {
  5. public:
  6. int NN,KK;
  7. double knightProbability(int N, int K, int r, int c) {
  8. NN = N;
  9. KK = K;
  10. memset(d,0,sizeof(d));
  11. d[0][r][c]=1;
  12. for(int k=0;k<K;++k){
  13. for(int i=0;i<N;++i){
  14. for(int j=0;j<N;++j){
  15. if(d[k][i][j]==0.0){
  16. continue;
  17. }
  18. for(int t=0;t<8;++t){
  19. const int nx = i + dx[t];
  20. const int ny = j + dy[t];
  21. if(in_board(nx,ny)){
  22. d[k+1][nx][ny] += d[k][i][j]/8;
  23. }
  24. }
  25. }
  26. }
  27. }
  28. double ans = 0;
  29. for(int i=0;i<N;++i){
  30. for(int j=0;j<N;++j){
  31. ans += d[K][i][j];
  32. }
  33. }
  34. return ans;
  35. }
  36. bool in_board(int x,int y){
  37. return x>=0 && x<NN && y>= 0 && y <NN;
  38. }
  39. };
  1. 三个无重叠子数组的最大和
    给定数组 nums 由正整数组成,找到三个互不重叠的子数组的最大和。

1,定义如下:
sums[i]代表以nums[i]结尾的前k个数的和
dp[i][j]代表截止到nums[i]形成的第j个无重叠子数组的最大和
path[i][j]代表截止到nums[i]形成的第j个无重叠子数组以哪个下标为结尾,用来回溯路径
2,状态转移方程为
dp[i][j] = max{dp[i - 1][j], sums[i] + dp[i - k][j - 1]};
对应的path[i][j] = path[i - 1][j]或i

  1. class Solution {
  2. public:
  3. vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
  4. vector<int> sum;
  5. int cur = 0;
  6. for(int i = 0; i < k; ++i){
  7. cur += nums[i];
  8. }
  9. sum.push_back(cur);
  10. for(int i = k; i < nums.size(); ++i){
  11. cur += nums[i] - nums[i - k];
  12. sum.push_back(cur);
  13. }
  14. int n = sum.size();
  15. vector<int> left(n, 0), right(n, n - 1);
  16. for(int i = 1; i < n; ++i){
  17. if(sum[i] > sum[left[i - 1]]) left[i] = i;
  18. else left[i] = left[i - 1];
  19. }
  20. for(int i = n - 2; i >= 0; --i){
  21. if(sum[i] >= sum[right[i + 1]]) right[i] = i;
  22. else right[i] = right[i + 1];
  23. }
  24. int mx = 0;
  25. vector<int> ans(3);
  26. for(int i = k; i < n - k; ++i){
  27. if(mx < sum[i] + sum[left[i - k]] + sum[right[i + k]]){
  28. mx = sum[i] + sum[left[i - k]] + sum[right[i + k]];
  29. ans = { left[i - k], i, right[i + k]};
  30. }
  31. }
  32. return ans;
  33. }
  34. };
  1. 员工的重要性
    现在输入一个公司的所有员工信息,以及单个员工 id ,返回这个员工和他所有下属的重要度之和。

哈希表存储后DFS或者广度优先均可

  1. /* // Definition for Employee. class Employee { public: int id; int importance; vector<int> subordinates; }; */
  2. class Solution {
  3. public:
  4. unordered_map<int, Employee *> mp;
  5. int dfs(int id) {
  6. Employee *employee = mp[id];
  7. int total = employee->importance;
  8. for (int subId : employee->subordinates) {
  9. total += dfs(subId);
  10. }
  11. return total;
  12. }
  13. int getImportance(vector<Employee *> employees, int id) {
  14. for (auto &employee : employees) {
  15. mp[employee->id] = employee;
  16. }
  17. return dfs(id);
  18. }
  19. };
  1. 贴纸拼词
    我们给出了 N 种不同类型的贴纸。每个贴纸上都有一个小写的英文单词。你希望从自己的贴纸集合中裁剪单个字母并重新排列它们,从而拼写出给定的目标字符串 target。如果你愿意的话,你可以不止一次地使用每一张贴纸,而且每一张贴纸的数量都是无限的。拼出目标 target 所需的最小贴纸数量是多少?如果任务不可能,则返回 -1。

状态压缩动态规划求解

  1. #define INF 0x3f3f3f3f
  2. class Solution {
  3. public:
  4. int minStickers(vector<string>& stickers, string target) {
  5. vector<int> dp(1 << 15, INF);
  6. int n = stickers.size(), m = target.size();
  7. vector<vector<int>> cnt(n, vector<int>(26));
  8. vector<vector<int>> can(26);
  9. for (int i = 0; i < n; ++i)
  10. for (char c : stickers[i]) {
  11. int d = c - 'a';
  12. cnt[i][d]++;
  13. if (can[d].empty() || can[d].back() != i)
  14. can[d].emplace_back(i);
  15. }
  16. dp[0] = 0;
  17. for (int i = 0; i < (1 << m) - 1; ++i) {
  18. if (dp[i] == INF)
  19. continue;
  20. int d;
  21. for (int j = 0; j < m; ++j) {
  22. if (!(i & (1 << j))) {
  23. d = j;
  24. break;
  25. }
  26. }
  27. d = target[d] - 'a';
  28. for (int k : can[d]) {
  29. int nxt = i;
  30. vector<int> left(cnt[k]);
  31. for (int j = 0; j < m; ++j) {
  32. if (nxt & (1 << j))
  33. continue;
  34. if (left[target[j] - 'a'] > 0) {
  35. nxt += (1 << j);
  36. left[target[j] - 'a']--;
  37. }
  38. }
  39. dp[nxt] = min(dp[nxt], dp[i] + 1);
  40. }
  41. }
  42. return dp[(1 << m) - 1] == INF ? -1 : dp[(1 << m) - 1];
  43. }
  44. };
  1. 前K个高频单词
    给一非空的单词列表,返回前 k 个出现次数最多的单词。
    哈希表+优先队列(堆)

    class Solution {
    public:

    1. vector<string> topKFrequent(vector<string>& words, int k) {
    2. unordered_map<string, int> cnt;
    3. for (auto& word : words) {
    4. cnt[word]++;
    5. }
    6. auto cmp = [](const pair<string, int>& a, const pair<string, int>& b) {
    7. return a.second == b.second ? a.first < b.first : a.second > b.second;
    8. };
    9. priority_queue<pair<string, int>, vector<pair<string, int>>, decltype(cmp)> que(cmp);
    10. for (auto& it : cnt) {
    11. que.emplace(it);
    12. if (que.size() > k) {
    13. que.pop();
    14. }
    15. }
    16. vector<string> ret(k);
    17. for (int i = k - 1; i >= 0; i--) {
    18. ret[i] = que.top().first;
    19. que.pop();
    20. }
    21. return ret;
    22. }

    };

发表评论

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

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

相关阅读