5173.质数序列
题目描述
请你帮忙给从 1 到 n 的数设计排列方案,使得所有的「质数」都应该被放在「质数索引」(索引从 1 开始)上;你需要返回可能的方案总数。
让我们一起来回顾一下「质数」:质数一定是大于 1 的,并且不能用两个小于它的正整数的乘积来表示。
由于答案可能会很大,所以请你返回答案 模 mod 10^9 + 7 之后的结果即可。
示例 1:
| 12
 3
 
 | 输入:n = 5输出:12
 解释:举个例子,[1,2,5,4,3] 是一个有效的排列,但 [5,2,3,4,1] 不是,因为在第二种情况里质数 5 被错误地放在索引为 1 的位置上。
 
 | 
示例 2:
提示:
解法
明白题意,质数所对应的索引只能放质数,当然非质数所对应的索引只能放非质数
所以我们可以求出质数的个数然后求全排列数x!,非质数的个数求全排列数y!,然后求x!*y!即为最后结果
注意每一步对10^9+7取余
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 
 | class Solution {public:
 int numPrimeArrangements(int n) {
 long long sumz=1;
 long long sumnz=1;
 int z=0;
 int nz=1;
 for(int i=2;i<=n;i++)
 {
 if(zhishu(i))
 {
 z++;
 sumz=sumz*z%(1000000007);
 }
 else
 {
 nz++;
 sumnz=sumnz*nz%(1000000007);
 }
 }
 int sum=(sumz*sumnz)%(1000000007);
 return sum;
 }
 bool zhishu(int i)
 {
 for(int k=2;k<=i/2;k++)
 {
 if(i%k==0)
 return false;
 }
 return true;
 }
 };
 
 | 
5174.健身计划评估
题目描述
你的好友是一位健身爱好者。前段日子,他给自己制定了一份健身计划。现在想请你帮他评估一下这份计划是否合理。
他会有一份计划消耗的卡路里表,其中 calories[i] 给出了你的这位好友在第 i 天需要消耗的卡路里总量。
为了更好地评估这份计划,对于卡路里表中的每一天,你都需要计算他 「这一天以及之后的连续几天」 (共 k 天)内消耗的总卡路里 T:
- 如果 T < lower,那么这份计划相对糟糕,并失去 1 分;
- 如果 T > upper,那么这份计划相对优秀,并获得 1 分;
- 否则,这份计划普普通通,分值不做变动。
请返回统计完所有 calories.length 天后得到的总分作为评估结果。
注意:总分可能是负数。
示例 1:
| 12
 3
 
 | 输入:calories = [1,2,3,4,5], k = 1, lower = 3, upper = 3输出:0
 解释:calories[0], calories[1] < lower 而 calories[3], calories[4] > upper, 总分 = 0.
 
 | 
示例 2:
| 12
 3
 
 | 输入:calories = [3,2], k = 2, lower = 0, upper = 1输出:1
 解释:calories[0] + calories[1] > upper, 总分 = 1.
 
 | 
示例 3:
| 12
 3
 
 | 输入:calories = [6,5,0,0], k = 2, lower = 1, upper = 5输出:0
 解释:calories[0] + calories[1] > upper, calories[2] + calories[3] < lower, 总分 = 0.
 
 | 
提示:
- 1 <= k <= calories.length <= 10^5
- 0 <= calories[i] <= 20000
- 0 <= lower <= upper
解题思路
理解题干,注意:每次计划表是移动1个单位,并不是移动k个单位
解法1:暴力
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | class Solution {public:
 int dietPlanPerformance(vector<int>& calories, int k, int lower, int upper) {
 int n=calories.size();
 int res=0;
 for(int i=0;i<=n-k;i++)
 {
 int sum=0;
 for(int j=0;j<k;j++)
 {
 sum+=calories[i+j];
 }
 if(sum<lower)
 res--;
 else if(sum>upper)
 res++;
 }
 return res;
 }
 };
 
 | 
解法2:动态规划
记录每个位置到开头总的消耗卡路里总量,计算a[i]与a[i-k]之差就可得到这份计划表的卡路里量
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | class Solution {public:
 int dietPlanPerformance(vector<int>& calories, int k, int lower, int upper) {
 int n=calories.size();
 int res=0;
 vector<int> a(n+1,0);
 for(int i=1;i<=n;i++)
 {
 a[i]=a[i-1]+calories[i-1];
 }
 for(int i=k;i<=n;i++)
 {
 int temp=a[i]-a[i-k];
 if(temp>upper)
 res+=1;
 else if(temp<lower)
 res-=1;
 }
 return res;
 }
 };
 
 | 
5175.构建回文串检测
题目描述
给你一个字符串 s,请你对 s 的子串进行检测。
每次检测,待检子串都可以表示为 queries[i] = [left, right, k]。我们可以 重新排列 子串 s[left], ..., s[right],并从中选择 最多 k 项替换成任何小写英文字母。 
如果在上述检测过程中,子串可以变成回文形式的字符串,那么检测结果为 true,否则结果为 false。
返回答案数组 answer[],其中 answer[i] 是第 i 个待检子串 queries[i] 的检测结果。
注意:在替换时,子串中的每个字母都必须作为 独立的 项进行计数,也就是说,如果 s[left..right] = "aaa" 且 k = 2,我们只能替换其中的两个字母。(另外,任何检测都不会修改原始字符串 s,可以认为每次检测都是独立的)
示例:
| 12
 3
 4
 5
 6
 7
 8
 
 | 输入:s = "abcda", queries = [[3,3,0],[1,2,0],[0,3,1],[0,3,2],[0,4,1]]输出:[true,false,false,true,true]
 解释:
 queries[0] : 子串 = "d",回文。
 queries[1] : 子串 = "bc",不是回文。
 queries[2] : 子串 = "abcd",只替换 1 个字符是变不成回文串的。
 queries[3] : 子串 = "abcd",可以变成回文的 "abba"。 也可以变成 "baab",先重新排序变成 "bacd",然后把 "cd" 替换为 "ab"。
 queries[4] : 子串 = "abcda",可以变成回文的 "abcba"。
 
 | 
提示:
- 1 <= s.length, queries.length <= 10^5
- 0 <= queries[i][0] <= queries[i][1] < s.length
- 0 <= queries[i][2] <= s.length
- s中只有小写英文字母
解题思路
同样是dp策略,构建dp数组a[n][26],对s字符串,记录从0到当前位置各个字符出现的次数;
然后分析queries 对于每个query来说
我们构建一个数组b[26] 来表示在这段字符串中每个字符出现的次数,我们通过计算a[r][i]-a[l-1][i]便能得到b[i]的值
判断b[i]里有多少个奇数c,若c//2<=k则能构成回文串,否则为false
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 
 | class Solution {public:
 vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
 int n=s.size();
 vector<vector<int>> a(n,vector<int>(26,0));
 a[0][s[0]-'a']++;
 for(int i=1;i<n;i++)
 {
 for(int j=0;j<26;j++)
 {
 a[i][j]=a[i-1][j];
 }
 a[i][s[i]-'a']++;
 }
 int m=queries.size();
 vector<bool> res(m,false);
 int i=0;
 for(auto query:queries)
 {
 int l=query[0];
 int r=query[1];
 int k=query[2];
 int b[26];
 for(int i=0;i<26;i++)
 {
 b[i]=a[r][i];
 if(l-1>=0)
 b[i]-=a[l-1][i];
 }
 int c=0;
 for(int i=0;i<26;i++)
 {
 c+=b[i]&1;
 }
 if(c/2<=k)
 res[i]=true;
 i++;
 }
 return res;
 }
 };
 
 | 
5176.猜字谜
题目描述
外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧。
字谜的迷面 puzzle 按字符串形式给出,如果一个单词 word 符合下面两个条件,那么它就可以算作谜底:
- 单词 word中包含谜面puzzle的第一个字母。
- 单词 word中的每一个字母都可以在谜面puzzle中找到。
 例如,如果字谜的谜面是 “abcdefg”,那么可以作为谜底的单词有 “faced”, “cabbage”, 和 “baggage”;而 “beefed”(不含字母 “a”)以及 “based”(其中的 “s” 没有出现在谜面中)。
返回一个答案数组 answer,数组中的每个元素 answer[i] 是在给出的单词列表 words 中可以作为字谜迷面 puzzles[i] 所对应的谜底的单词数目。
示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 输入:words = ["aaaa","asas","able","ability","actt","actor","access"],
 puzzles = ["aboveyz","abrodyz","abslute","absoryz","actresz","gaswxyz"]
 输出:[1,1,3,2,4,0]
 解释:
 1 个单词可以作为 "aboveyz" 的谜底 : "aaaa"
 1 个单词可以作为 "abrodyz" 的谜底 : "aaaa"
 3 个单词可以作为 "abslute" 的谜底 : "aaaa", "asas", "able"
 2 个单词可以作为 "absoryz" 的谜底 : "aaaa", "asas"
 4 个单词可以作为 "actresz" 的谜底 : "aaaa", "asas", "actt", "access"
 没有单词可以作为 "gaswxyz" 的谜底,因为列表中的单词都不含字母 'g'。
 
 | 
提示:
- 1 <= words.length <= 10^5
- 4 <= words[i].length <= 50
- 1 <= puzzles.length <= 10^4
- puzzles[i].length == 7
- words[i][j],- puzzles[i][j]都是小写英文字母。
- 每个 puzzles[i]所包含的字符都不重复。
解题思路
此题借鉴大佬:小白二号
思路:
1.首先构建一个map数组map<pair<int,int>,int> wordmap;用来存每个单词  由值对做键,数量做值(学到了,可以这样建map)
2.pair中第一个int 表示该word中个字母组成的bitset用int表示的数,第二个int是用来判断是否存在puzzle[i]的第一个字母,已确定能否让res[i]的个数加1
技巧1:用int bit 存一个单词中每个字母是否出现过,因为字母只有26个 int可以表示32位,我们可以用二进制每一个位置来表示不同的字母,如$(1)_2$表示a,$(10)_2$表示b,依次类推
技巧2:遍历puzzle的子集,同样通过位运算来遍历,
首先我们知道puzzle的非空子集总共为(1<<len)-1个即127个,然后我们同样创建bit来表示该子集中的字母用int表示的数,通过i与(1<<j)进行&运算,可知puzzle[j]能否放入该子集中,若能,我们再进行bit=bit与(1<<(puzzle[j]-‘a’))进行|运算,将其加入到bit中,最后我们将bit放入 ret数组,外层循环遍历完,返回ret数组
3.遍历puzzle[i]的子集sub,count+=map[make_pair(sub,pubble[0]-‘a’)] 
count即为puzzle[i]的答案数组res[i]对应的数值
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 
 | class Solution {public:
 vector<int> findNumOfValidWords(vector<string>& words, vector<string>& puzzles) {
 map<pair<int,int>,int> wordmap;
 for(auto word:words)
 {
 int count=0;
 int bit=0;
 for(auto c:word)
 {
 int index=c-'a';
 if(bit&(1<<index))
 {
 }
 else
 {
 bit+=(1<<index);
 count++;
 }
 }
 if(count>=8)
 continue;
 for(int i=0;i<26;i++)
 {
 if(bit&(1<<i))
 wordmap[make_pair(bit,i)]++;
 }
 }
 vector<int> res;
 for(auto puzzle:puzzles)
 {
 vector<int> temp=make(puzzle);
 int count=0;
 for(auto sub:temp)
 {
 count +=wordmap[make_pair(sub,puzzle[0]-'a')];
 }
 res.push_back(count);
 }
 return res;
 }
 vector<int> make(string puzzle)
 {
 int len=puzzle.size();
 vector<int> ret;
 for(int i=1;i<(1<<len);i++)
 {
 int bit=0;
 for(int j=0;j<len;j++)
 {
 if(i&(1<<j))
 {
 bit=bit|(1<<puzzle[j]-'a');
 }
 }
 ret.push_back(bit);
 }
 return ret;
 }
 };
 
 | 
时间复杂度:O($10^4 *(2^7-1)$) puzzles最长10^4 puzzle 又长度固定为7 所以每个的子集 固定为2^7个 ,所以这样时间不会超限