- 收藏清单
给你一个数组 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;
}
};
- 圆形靶内的最大飞镖数量
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;
}
};
- 检查单词是否为句中其他单词的前缀
给你一个字符串 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;
}
};
- 定长子串中元音的最大数目
给你字符串 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 到 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);
}
};
- 两个子序列的最大点积
给你两个数组 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()];
}
};