leetcode解题思路分析(一百六十八)1452 - 1458 题

  1. 收藏清单
    给你一个数组 favoriteCompanies ,其中 favoriteCompanies[i] 是第 i 名用户收藏的公司清单(下标从 0 开始)。请找出不是其他任何人收藏的公司清单的子集的收藏清单,并返回该清单下标。下标需要按升序排列。

把字符串匹配转变成哈希后的数字匹配。

cpp 复制代码
class Solution {
public:
    unordered_set <string> s[100 + 5];
    vector<int> peopleIndexes(vector<vector<string>>& favoriteCompanies) {
        int n = favoriteCompanies.size();
        vector <int> ans;

        for (int i = 0; i < n; ++i) {
            for (const auto &com: favoriteCompanies[i]) {
                s[i].insert(com);
            }
        }

        auto check = [=] (int x, int y) -> bool {
            for (const auto &com: favoriteCompanies[x]) {
                if (s[y].find(com) == s[y].end()) {
                    return false;
                }
            }
            return true;
        };

        for (int i = 0; i < n; ++i) {
            bool isSub = false;
            for (int j = 0; j < n; ++j) {
                if (i == j) {
                    continue;
                }
                isSub |= check(i, j);
            }
            if (!isSub) {
                ans.push_back(i);
            }
        }

        return ans;
    }
};
  1. 圆形靶内的最大飞镖数量
    Alice 向一面非常大的墙上掷出 n 支飞镖。给你一个数组 darts ,其中 darts[i] = [xi, yi] 表示 Alice 掷出的第 i 支飞镖落在墙上的位置。Bob 知道墙上所有 n 支飞镖的位置。他想要往墙上放置一个半径为 r 的圆形靶。使 Alice 掷出的飞镖尽可能多地落在靶上。给你整数 r ,请返回能够落在 任意 半径为 r 的圆形靶内或靶上的最大飞镖数。

本题有几种思路。思路一:假设有一个圆覆盖了一些点,则通过平移可以让一个点在圆上,固定该点可以让至少一个点再次出现在圆上且覆盖的点不减少。由此,我们可以遍历所有的两个点构成的圆,归纳所有的圆心位置,然后求每个圆心内有多少个点,即可给出最终答案。思路二:每个点为圆心画一个圆,则会覆盖一定范围,相交次数最多的区域即点位的范围。

cpp 复制代码
struct point{
    double x,y;
    point(double i,double j):x(i),y(j){}
};

//算两点距离
double dist(double x1,double y1,double x2,double y2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

//计算圆心
point f(point& a,point& b,int r){
    //算中点
    point mid((a.x+b.x)/2.0,(a.y+b.y)/2.0);
    //AB距离的一半
    double d=dist(a.x,a.y,mid.x,mid.y);
    //计算h
    double h=sqrt(r*r-d*d);
    //计算垂线
    point ba(b.x-a.x,b.y-a.y);
    point hd(-ba.y,ba.x);
    double len=sqrt(hd.x*hd.x+hd.y*hd.y);
    hd.x/=len,hd.y/=len;
    hd.x*=h,hd.y*=h;
    return point(hd.x+mid.x,hd.y+mid.y);
}

class Solution {
public:
    int numPoints(vector<vector<int>>& points, int r) {
        int n=points.size();
        int ans=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(i==j){//一个点
                    int cnt=0;
                    for(int k=0;k<n;k++){
                        double tmp=dist(points[i][0],points[i][1],points[k][0],points[k][1]);
                        if(tmp<=r) cnt++;
                    }
                    ans=max(cnt,ans);
                }else{//两个点
                    //通过长度判断有没有圆心
                    double d=dist(points[i][0],points[i][1],points[j][0],points[j][1]);
                    if(d/2>r) continue;

                    point a(points[i][0],points[i][1]),b(points[j][0],points[j][1]);
                    point res=f(a,b,r);
                    int cnt=0;
                    for(int k=0;k<n;k++){
                        double tmp=dist(res.x,res.y,points[k][0],points[k][1]);
                        if(tmp<=r) cnt++;
                    }
                    ans=max(cnt,ans);
                }
            }
        }
        return ans;
    }
};
  1. 检查单词是否为句中其他单词的前缀
    给你一个字符串 sentence 作为句子并指定检索词为 searchWord ,其中句子由若干用 单个空格 分隔的单词组成。请你检查检索词 searchWord 是否为句子 sentence 中任意单词的前缀。如果 searchWord 是某一个单词的前缀,则返回句子 sentence 中该单词所对应的下标(下标从 1 开始)。如果 searchWord 是多个单词的前缀,则返回匹配的第一个单词的下标(最小下标)。如果 searchWord 不是任何单词的前缀,则返回 -1 。字符串 s 的 前缀 是 s 的任何前导连续子字符串。

挨个匹配检索即可。

cpp 复制代码
class Solution {
public:
    bool isPrefix(const string &sentence, int start, int end, const string &searchWord) {
        for (int i = 0; i < searchWord.size(); i++) {
            if (start + i >= end || sentence[start + i] != searchWord[i]) {
                return false;
            }
        }
        return true;
    }

    int isPrefixOfWord(string sentence, string searchWord) {
        int n = sentence.size(), index = 1, start = 0, end = 0;
        while (start < n) {
            while (end < n && sentence[end] != ' ') {
                end++;
            }
            if (isPrefix(sentence, start, end, searchWord)) {
                return index;
            }

            index++;
            end++;
            start = end;
        }
        return -1;
    }
};
  1. 定长子串中元音的最大数目
    给你字符串 s 和整数 k 。
    请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。
    英文中的 元音字母 为(a, e, i, o, u)。

双指针滑动

cpp 复制代码
class Solution {
public:
    int maxVowels(string s, int k) {
        int ret = 0, curr = 0;
        int left = 0, right = k - 1, size = s.size();
        for (int i = 0; i <= right; ++i) {
            if (_key_set.count(s[i])) {
                curr++;
            }
        }
        ret = curr;
        while (right <= size) {
            if (_key_set.count(s[left])) { curr--; }
            left++;
            right++;
            if (right > size) {break;}
            if (_key_set.count(s[right])) { curr++; }
            ret = max(ret, curr);
        }
        return ret;
    }
private:
    std::unordered_set<char> _key_set = {'a', 'e', 'i', 'o', 'u'};
};
  1. 二叉树中的伪回文路径
    给你一棵二叉树,每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的,当它满足:路径经过的所有节点值的排列中,存在一个回文序列。请你返回从根到叶子节点的所有路径中 伪回文 路径的数目。

如果 mask 中只有一个 1,那么去掉这个 1 之后,mask 就变成 0 了

cpp 复制代码
/**
 * 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 pseudoPalindromicPaths(TreeNode* root, int mask = 0) {
        if (root == nullptr) {
            return 0;
        }
        mask ^= 1 << root->val; // 修改 root->val 出现次数的奇偶性
        if (root->left == nullptr && root->right == nullptr) { // root 是叶子节点
            return (mask & (mask - 1)) == 0;
        }
        return pseudoPalindromicPaths(root->left, mask) +
               pseudoPalindromicPaths(root->right, mask);
    }
};
  1. 两个子序列的最大点积
    给你两个数组 nums1 和 nums2 。
    请你返回 nums1 和 nums2 中两个长度相同的 非空 子序列的最大点积。
    数组的非空子序列是通过删除原数组中某些元素(可能一个也不删除)后剩余数字组成的序列,但不能改变数字间相对顺序。比方说,[2,3,5] 是 [1,2,3,4,5] 的一个子序列而 [1,5,3] 不是。

动态规划经典题目,用dp[i][j]表示数组1选i和数组2选j的最值,则和i-1,j;i-1,j-1;i,j-1相关

cpp 复制代码
class Solution {
public:
    int maxDotProduct(vector<int>& nums1, vector<int>& nums2) {
        int dp[501][501];
        for(int i = 0; i <= nums1.size(); i++) {
            for(int j = 0; j <= nums2.size(); j++) {
                dp[i][j] = -1000*1000*500;
            }
        }
        for(int i = 1; i <= nums1.size(); i++) {
            for(int j = 1; j <= nums2.size(); j++) {
                int a = nums1[i-1];
                int b = nums2[j-1];
                dp[i][j] = max(dp[i][j], a*b);
                dp[i][j] = max(dp[i][j], dp[i-1][j-1] + a*b);
                dp[i][j] = max(dp[i][j], dp[i-1][j-1]);
                dp[i][j] = max(dp[i][j], dp[i-1][j]);
                dp[i][j] = max(dp[i][j], dp[i][j-1]);
            }
        }
        return dp[nums1.size()][nums2.size()];
    }
};
相关推荐
沐浴露z3 小时前
详解 MySQL 自适应哈希
数据库·mysql·哈希算法
哼?~3 小时前
算法学习--离散化
算法
AI科技星3 小时前
引力编程时代:人类文明存续与升维
数据结构·人工智能·经验分享·算法·计算机视觉
Blossom.1188 小时前
移动端部署噩梦终结者:动态稀疏视觉Transformer的量化实战
java·人工智能·python·深度学习·算法·机器学习·transformer
轻微的风格艾丝凡8 小时前
卷积的直观理解
人工智能·深度学习·神经网络·算法·计算机视觉·matlab·cnn
田梓燊11 小时前
红黑树分析 1
算法
晚风吹长发11 小时前
二分查找算法+题目详解
c++·算法·二分查找
悠悠~飘11 小时前
18.PHP基础-递归递推算法
算法·php
pilgrim5312 小时前
结合 Leetcode 题探究KMP算法
算法·leetcode