LeetCode第 94 场双周赛
1.最多可以摧毁的敌人城堡数目
题目
Solution
可以第一重循环找到\(1\),然后从该位置分别向左和向又寻找\(-1\),寻找过程中遇到\(1\)则停止,不更新ans,遇到\(-1\)则更新ans。
class Solution {
public:
int captureForts(vector<int>& forts) {
int ans = -1;
int n = forts.size();
for(int i = 0;i < forts.size();i++){
if(forts[i] == 1){
for(int j = 1;j <= forts.size() - 1 && i + j <= n-1;j++){
if(forts[i+j] == 1) break;
if(forts[i+j] == -1){
ans = max(ans,j);
break;
}
}
for(int j = 1;j <= forts.size()-1 && i - j >= 0 && i != 0; j++){
if(forts[i-j] == 1) break;
if(forts[i-j] == -1){
ans = max(ans,j);
break;
}
}
}
}
return ans-1 > 0? ans-1:0;
}
};
2.奖励最顶尖的 K 名学生
Solution
class Solution {
public:
vector<int> topStudents(vector<string>& positive_feedback, vector<string>& negative_feedback, vector<string>& report, vector<int>& student_id, int k) {
unordered_set<string> positive;
unordered_set<string> negative;
for(auto &a : positive_feedback){
positive.insert(a);
}
for(auto &a : negative_feedback){
negative.insert(a);
}
unordered_map<int,int> book(student_id.size());
for(int i = 0;i < report.size();i++){
stringstream ss;
string a;
ss << report[i];//将一句话单词放入
while(ss>>a){//对每个单词进行检测
if(positive.find(a) != positive.end()){
book[student_id[i]] += 3;
}else if(negative.find(a) != negative.end()){
book[student_id[i]] -= 1;
}
}
}
sort(student_id.begin(),student_id.end(),[&] (int a, int b){
if(book[a] < book[b]) return false;
else if(book[a] > book[b]) return true;
else return a < b;
});
return vector<int>(student_id.begin(),student_id.begin() + k);
}
};
3.最小化两个数组中的最大值
Solution
二分答案,每次对二分出来的数进行检测看能否选出题目要求的数的个数,因为每次二分检测的是数的个数,而检测不能被整除的数的个数不如检测能被整除的数的个数容易,所以我们可以先求出能被\(divisor\)整除的数的个数,然后减去这些数,得到不能被整除的数的个数,\(0~k\)之间能被\(divisor\)整除的数的个数我们用\(k / divisor\)可以求得。
注意,check和lcm要用long long,不然会WA。
class Solution {
public:
int minimizeSet(int divisor1, int divisor2, int uniqueCnt1, int uniqueCnt2) {
int l = uniqueCnt1 + uniqueCnt2,r = INT_MAX;
auto check = [&](long long k,long long d1,long long d2,long long c1,long long c2){
//c11代表0~k中有多少个数能被d1整除,c22代表0~k中有多少个数能被d2整除,c12是多少个数能被d1和d2整除
long long c11 = k / d1, c22 = k / d2, c12 = k / (lcm(d1,d2));
c11 = c11 - c12;//现在表示能被放入arr2中数的个数
c22 = c22 - c12;//现在表示能被放入arr1中数的个数
k = k - c12;//现在表示有多少个数可以被选择
if(c11 > c2){
k -= (c11 - c2);
}
if(c22 > c1){
k -= (c22 - c1);
}
return k >= (c1+c2);
};
auto lcm = [&](long long a,long long b){
return a * b / gcd(a,b);
};
while(l < r){
int mid = l + (r - l) / 2;
//cout<<"l:"<<l<<" "<<"r:"<<r<<endl;
if(check(mid,divisor1,divisor2,uniqueCnt1,uniqueCnt2)){
r = mid;
}else{
l = mid+1;
}
}
return l;
}
private:
int gcd(int a, int b) {
while(b){
int t = a;
a = b;
b = t % b;
}
return a;
}
};
4. 统计同位异构字符串数目
Solution
对每个单词求全排列在将各自的全排列乘起来,这道题困难就困难在求全排列,全排列的阶乘可能会很大,所以要用逆元求解。
class Solution {
long long mod = 1e9+7;
long solve(string &s){//计算全排列
unordered_map<int,int> memo;//用来存放质因数出现的次数
vector<int> cnt(26);//存放每个字母出现的次数
for(char &c:s)
++cnt[c-'a'];
for(int num=2;num<=s.size();++num)//对分子——元素个数的阶乘作质因数分解
{
int n=num;
for(int i = 2; i <= sqrt(n); i ++)
if(n % i == 0)
while(n % i == 0)
{
++memo[i];
n /= i;
}
if(n != 1)
++memo[n];
}
for(int k:cnt)
for(int num=2;num<=k;++num)//对每个重复次数的阶乘作质因数分解,并从memo中减掉
{
int n=num;
for(int i = 2; i <= sqrt(n); i ++)
if(n % i == 0)
while(n % i == 0)
{
--memo[i];
n /= i;
}
if(n != 1)
--memo[n];
}
long ans=1;
for(auto &p:memo)//对分子剩下的质因数作乘法
while(p.second)
ans=(ans*p.first)%mod,--p.second;
return ans;
}
public:
int countAnagrams(string s) {
long long ans = 1;
stringstream ss(s);
string str;
while(ss >> str){
ans = (ans*solve(str)) % mod;
}
return ans;
}
};