Leetcode-第154场周赛

1189.”气球”的最大数量

给你一个字符串 text,你需要使用 text 中的字母来拼凑尽可能多的单词 “balloon”(气球)

字符串 text 中的每个字母最多只能被使用一次。请你返回最多可以拼凑出多少个单词 **”balloon”**。

示例 1:

img

1
2
输入:text = "nlaebolko"
输出:1

示例 2:

img

1
2
输入:text = "loonbalxballpoon"
输出:2

示例 3:

1
2
输入:text = "leetcode"
输出:0

提示:

  • 1 <= text.length <= 10^4
  • text 全部由小写英文字母组成
解法1:

简单题。

思路:

创建一个hash表来存各个字母的出现次数,找a,b,l/2,o/2,n的最小值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int maxNumberOfBalloons(string text) {
int n=text.size();
vector<int> res(26,0);
for(int i=0;i<n;i++)
{
res[text[i]-'a']++;
}
int mins=INT_MAX;
mins=min(mins,res[0]);
mins=min(mins,res[1]);
mins=min(mins,res[11]/2);
mins=min(mins,res[13]);
mins=min(mins,res[14]/2);
return mins;
}
};

1190.反转每对括号间的子串

给出一个字符串 s(仅含有小写英文字母和括号)。

请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。

注意,您的结果中 不应 包含任何括号。

示例 1:

1
2
输入:s = "(abcd)"
输出:"dcba"

示例 2:

1
2
输入:s = "(u(love)i)"
输出:"iloveu"

示例 3:

1
2
输入:s = "(ed(et(oc))el)"
输出:"leetcode"

示例 4:

1
2
输入:s = "a(bcdefghijkl(mno)p)q"
输出:"apmnolkjihgfedcbq"

提示:

  • 0 <= s.length <= 2000
  • s 中只有小写英文字母和括号
  • 我们确保所有括号都是成对出现的
解法1:栈

思路:用栈存左括号出现位置,当遇见右括号时,翻转从栈顶值左括号到这个右括号的子串。

再遍历一遍字符串,将不是左右括号的字符挨个存入结果字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
string reverseParentheses(string s) {
stack<int> st;
string res="";
int n=s.length();
for(int i=0;i<n;i++)
{
if(s[i]=='(')
st.push(i);
else if(s[i]==')')
{
int t=st.top();
st.pop();
reverse(s.begin()+t,s.begin()+i);
}
}
for(int i=0;i<n;i++)
{
if(s[i]!='('&&s[i]!=')')
res+=s[i];
}
return res;
}
};

1191.K次串联后最大子数组之和

给你一个整数数组 arr 和一个整数 k

首先,我们要对该数组进行修改,即把原数组 arr 重复 k 次。

举个例子,如果 arr = [1, 2]k = 3,那么修改后的数组就是 [1, 2, 1, 2, 1, 2]

然后,请你返回修改后的数组中的最大的子数组之和。

注意,子数组长度可以是 0,在这种情况下它的总和也是 0

由于 结果可能会很大,所以需要 模(mod) 10^9 + 7 后再返回。

示例 1:

1
2
输入:arr = [1,2], k = 3
输出:9

示例 2:

1
2
输入:arr = [1,-2,1], k = 5
输出:2

示例 3:

1
2
输入:arr = [-1,-2], k = 7
输出:0

提示:

  • 1 <= arr.length <= 10^5
  • 1 <= k <= 10^5
  • -10^4 <= arr[i] <= 10^4
解法1:前缀和,后缀和

先计算出arr数组的总和,然后分两种情况进行讨论

1.若sum>0&&k>2

​ 这种情况我们可以求出arr数组的最大前缀和(即复制到最右边的数组应该取的值)和最大后缀和(即最左边数组应该取的值)因为中间每个arr的和sum>0所以我们肯定要加上每个sum。

2.

​ (1).若k>1,我们复制一次arr。

​ (2)找到arr这个数组的最大子序和即为所求结果。

注意:中间数字用int会溢出,所以我们用long long 存数组,最后结果mod10^9+7.

1
2
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
class Solution {
public:
int kConcatenationMaxSum(vector<int>& arr, int k) {
int mod=pow(10,9)+7;
int n=arr.size();
vector<long long> sum(n+1,0);
for(int i=1;i<n+1;i++)
{
sum[i]=sum[i-1]+arr[i-1];
}
long long res=0;
if(sum[n]>0&&k>2)
{
long long frist=0,last=0;
for(int i=0;i<n+1;i++)
{
frist=max(frist,sum[n]-sum[n-i]);
last=max(last,sum[i]);
}
res=frist+last+(k-2)*sum[n];
}
else
{
vector<int> temp(arr);
if(k>1)
{
for(auto x:arr)
{
temp.push_back(x);
}
}
long long sum_t=0;
for(int i=0;i<temp.size();i++)
{
if(sum_t>0)
sum_t+=temp[i];
else sum_t=temp[i];
res=max(res,sum_t);
}
}
return res%mod;
}
};

1192.查找集群内的「关键连接」

力扣数据中心有 n 台服务器,分别按从 0n-1 的方式进行了编号。

它们之间以「服务器到服务器」点对点的形式相互连接组成了一个内部集群,其中连接 connections 是无向的。

从形式上讲,connections[i] = [a, b] 表示服务器 ab 之间形成连接。任何服务器都可以直接或者间接地通过网络到达任何其他服务器。

「关键连接」是在该集群中的重要连接,也就是说,假如我们将它移除,便会导致某些服务器无法访问其他服务器。

请你以任意顺序返回该集群内的所有 「关键连接」。

示例 1:

img

1
2
3
输入:n = 4, connections = [[0,1],[1,2],[2,0],[1,3]]
输出:[[1,3]]
解释:[[3,1]] 也是正确的。

提示:

  • 1 <= n <= 10^5
  • n-1 <= connections.length <= 10^5
  • connections[i][0] != connections[i][1]
  • 不存在重复的连接
解法1:Tarjan算法

找到图中的割点问题。用Tarjan算法实现。

算法实现步骤:

1.定义dfn[i]数组表示dfs遍历时的i点的次序从1开始

2.定义low[i]数组表示i点不经过父节点能到达编号最小的点的数值

3.定义father[i]数组表示i点的父节点

4.遍历connections数组将每个边的两端记录下来。然后进行tarjan算法。

​ tarjan算法:

​ 对每个点设置父节点,dfs遍历次序dfn[i]的值,默认low[i]值为dfs[i],对与i直接相连的点进行遍历,设为to,

(1)to为父节点跳过,

(2)dfn[to]==-1表示还未遍历,进行tarjan(to,i),然后low[i]在low[i]和low[to]选择一个最小值

(3)若已经遍历dfn[to] low[i]在low[i]和dfn[to]选择一个最小值

5.进行完tarjan算法,遍历所有点,判断父节点dfn[f]和low[i]关系,若low[i]>dfn[f]表示i点必须经过父节点f才能访问到f也就意味着(i,f)这条边是一个割边。

1
2
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
61
62
class Solution {
private:
vector<vector<int>> _g;
vector<int> _low;
vector<int> _dfn;
vector<int> _father;
int time;
public:
vector<vector<int>> criticalConnections(int n, vector<vector<int>>& connections) {
vector<vector<int>> g(n+1);
vector<int> low(n+1,-1);
vector<int> dfn(n+1,-1);
vector<int> father(n+1);
vector<vector<int>> res;
if(n==1)
return res;
this->_g=g;
this->_low=low;
this->_dfn=dfn;
this->_father=father;
time=0;
for(auto temp:connections)
{
int from=temp[0]+1,to=temp[1]+1;
_g[from].push_back(to);
_g[to].push_back(from);
}
tarjan(1,0); //从编号1点开始dfs 1的父节点假设为0
for(int i=1;i<=n;i++)
{
int f=_father[i];
if(f>0&&_low[i]>_dfn[f])
{
vector<int> re;
re.push_back(i-1);
re.push_back(f-1);
res.push_back(re);
}
}
return res;
}
void tarjan(int i,int ifather)
{
_father[i]=ifather;
time++;
_low[i]=time;
_dfn[i]=time;
for(int j=0;j<_g[i].size();j++)
{
int to=_g[i][j];
if(ifather==to)
continue;
if(_dfn[to]==-1)
{
tarjan(to,i);
_low[i]=min(_low[i],_low[to]);
}
else
_low[i]=min(_low[i],_dfn[to]);
}
}
};