Rank:1121 / 4148 AC 2/4
题目传送
5364. 按既定顺序创建目标数组
签到题
当时手写的数组后移,其实可以用vector的insert…
class Solution {
public:
vector<int> createTargetArray(vector<int>& nums, vector<int>& index) {
int n = index.size();
vector<int> target(n,-1);
for(int i=0;i<n;i++){
if(target[index[i]]!=-1){
for(int j=n-1;j>index[i];j--){
if(j>0)target[j] = target[j-1];
}
target[index[i]] = nums[i];
}
else target[index[i]] = nums[i];
}
return target;
}
};
insert 版本
class Solution {
public:
vector<int> createTargetArray(vector<int>& nums, vector<int>& index) {
int n = index.size();
vector<int> target;
for(int i=0;i<n;i++){
target.insert(target.begin()+index[i],nums[i]);
}
return target;
}
};
平均时间复杂度 O ( n 2 ) O(n^2) O(n2)
5178. 四因数
这里有个唯一分解定理,大概是任意一个数x都可以被分解成素数的乘积
x
=
p
1
a
1
∗
p
2
a
2
∗
p
3
a
3
∗
p
4
a
4
∗
.
.
.
.
.
p
s
a
s
x = p_1^{a_1}*p_2^{a_2}*p_3^{a_3}*p_4^{a_4}*.....p_s^{a_s}
x=p1a1∗p2a2∗p3a3∗p4a4∗.....psas
因子的个数:
∏
j
=
1
s
(
a
j
+
1
)
\prod_{j=1}^s (a_j+1)
j=1∏s(aj+1)
因子的和:
∏
j
=
1
s
p
j
a
j
+
1
−
1
p
j
−
1
\prod_{j=1}^s \frac {p_j^{a_j+1}-1}{p_j-1}
j=1∏spj−1pjaj+1−1
class Solution {
public:
int fun(int n,long long &sum){
long long s = 1;
sum = 1;
for(int i=2;i*i<=n;i++){
int cnt = 0,a=1;
while(n%i==0){
n /= i;
a *= i;
cnt++;
}
s = s*(cnt+1);
sum = sum*(a*i-1)/(i-1);
}
if(n>1) {
s = s*2;sum = sum*(n+1);
}
if(s!=4) sum = 0;
return s;
}
int sumFourDivisors(vector<int>& nums) {
long long sum = 0;
long long s= 0;
for(int i=0;i<nums.size();i++){
fun(nums[i],s);
sum += s;
}
return sum;
}
};
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
5366. 检查网格中是否存在有效路径
题目稍微变化一下,就不会写了…
参考:建图+dfs 40 行左右
大题思路是: 把原来每个方格,再变成3*3的小格子,然后在去标记,就类似走迷宫。
class Solution {
public:
int maps[1000][1000];
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1},m,n;
void fill(int i,int j,int s){
maps[i+1][j+1] =1;
if(s==1) maps[i+1][j]=maps[i+1][j+2] =1;
else if(s==2) maps[i][j+1] = maps[i+2][j+1] =1;
else if(s==3) maps[i+1][j] = maps[i+2][j+1] = 1;
else if(s==4) maps[i+2][j+1] = maps[i+1][j+2] = 1;
else if(s==5) maps[i+1][j] = maps[i][j+1] = 1;
else if(s==6) maps[i][j+1] = maps[i+1][j+2] = 1;
}
void dfs(int i,int j){
maps[i][j] = 0;
for(int k=0;k<4;k++){
int x = i+dx[k],y = j+dy[k];
if(x>=0&&x<3*m&&y>=0&&y<3*n&&maps[x][y])
dfs(x,y);
}
}
bool hasValidPath(vector<vector<int>>& g) {
m = g.size(),n = g[0].size();
memset(maps,0,sizeof(maps));
for(int i=0;i<3*m;i+=3){
for(int j=0;j<3*n;j+=3){
fill(i,j,g[i/3][j/3]);
}
}
dfs(1,1);
return maps[3*m-2][3*n-2] == 0;
}
};
时间复杂度 O ( m ∗ n ) O(m*n) O(m∗n)
5367. 最长快乐前缀
题目让求的是最长的既是前缀也是后缀的字符串。
其实直接暴力求解,对比子串的话,会爆内存。
最长的既是前缀也是后缀的字符串,其实kmp算法的next数组就是记录了这个字符串的长度,next[j]代表 [0, j - 1] 区段中最长相同真前后缀的长度,这里提到了真前缀,真后缀,区别于前缀、后缀,就是不包括原字符串本身。所以next[len]就记录了原字符串的最长相同的真前后缀的长度,其实len为原字符串的长度。
class Solution {
public:
string longestPrefix(string s) {
int next[100010];
int k=-1,i=0,len = s.length();
next[0] = -1;
while(i<len){
if(k==-1||s[i]==s[k]){
k++;i++;
next[i] = k;
}
else k = next[k];
}
if(next[len]==0) return "";
return s.substr(0,next[len]);
}
};
时间复杂度
O
(
n
)
O(n)
O(n)
Hash解法
整体的思路是 如果两个字符串的hash相同,则可以认为两个字符串是相同的
参考《算法进阶指南》字符串hash章节
建议使用模数为
2
64
2^{64}
264,这样的话,直接使用 unsigned long long 即可,还能避免取模运算,这样会自动截断或取模。
常用位权p,有131,13331,书上说这样的Hash算法很难产生冲突。
H
a
s
h
(
T
)
=
H
a
s
h
(
S
+
T
)
−
H
a
s
h
(
S
)
∗
P
l
e
n
g
t
h
(
T
)
Hash(T) = Hash(S+T)-Hash(S)*P^{length(T)}
Hash(T)=Hash(S+T)−Hash(S)∗Plength(T)
其中S、T均为字符串。
typedef unsigned long long ull;
const int maxn = 1e5+10;
class Solution {
public:
string longestPrefix(string s) {
int p = 131,len = s.length(),res=0;
ull H[maxn],w[maxn];
H[0] = 0;w[0] = 1;
for(int i=1;i<=len;i++){
H[i] = H[i-1]*p+s[i-1]-'a'+1;
w[i] = w[i-1]*p;
}
for(int i=1;i<len;i++){
ull pre = H[i];
// ull post = H[len]-H[len-i]*(ull)pow(p,i); //如果使用pow绩点要用ull强转一下
ull post = H[len]-H[len-i]*w[i];
if(pre==post) res = i;
}
return s.substr(0,res);
}
};
时间复杂度 O ( n ) O(n) O(n)