后话
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
对于面试,说几句个人观点。
面试,说到底是一种考试。正如我们一直批判应试教育脱离教育的本质,为了面试学习技术也脱离了技术的初心。但考试对于人才选拔的有效性是毋庸置疑的,几千年来一直如此。除非你有实力向公司证明你足够优秀,否则,还是得乖乖准备面试。这也并不妨碍你在通过面试之后按自己的方式学习。
其实在面试准备阶段,个人的收获是很大的,我也认为这是一种不错的学习方式。首先,面试问题大部分基础而且深入,这些是平时工作的基础。就好像我们之前一直不明白学习语文的意义,但它的意义就在每天的谈话间。
所谓面试造火箭,工作拧螺丝。面试往往有更高的要求,也迫使我们更专心更深入地去学习一些知识,也何尝不是一种好事。
间
(
言
下
之
意
长
度
是
偶
数
)
2、中心点在字符之间(言下之意长度是偶数)
2、中心点在字符之间(言下之意长度是偶数)
或者
d
a
l
a
o
i
c
e
u
p
dalaoiceup
dalaoiceup的添加’#'字符法也可行!
然后从中心点往左右延伸就行了,复杂度
O
(
T
n
2
)
O(Tn^2)
O(Tn2)
但是由于出题人太过于良心,暴力不仅能过竟然还是
0
m
s
0ms
0ms!一时语塞
.
j
p
g
.jpg
.jpg
为啥过不了,自己可以构造一个长度
10000
10000
10000全是一样字符的字符串,跑跑就知道了。
正解:
M
a
n
a
c
h
e
r
Manacher
Manacher马拉车算法,复杂度
O
(
T
n
)
O(Tn)
O(Tn)
首先,要做个预处理,在字符串头加’KaTeX parse error: Expected 'EOF', got '#' at position 9: ’,字符之间加’#̲’,避免了讨论。 如"a…#a#b#b#a#",而在开头加美元的目的,是为了让"偶数"和"奇数"型回文串的信息一致化。
简单地来说,就是利用了一个对称点(k),复制了当前点(i)关于点(k)的对称点(j)的信息。
我们不妨设
p
[
i
]
:
以
i
为
中
心
位
置
的
最
大
回
文
子
串
半
径
p[i]:以i为中心位置的最大回文子串半径
p[i]:以i为中心位置的最大回文子串半径
m
s
:
当
前
最
大
的
延
伸
点
,
即
m
a
x
(
p
[
k
]
k
)
ms:当前最大的延伸点,即max(p[k]+k)
ms:当前最大的延伸点,即max(p[k]+k)
i
d
:
最
大
延
伸
回
文
串
的
中
心
点
id:最大延伸回文串的中心点
id:最大延伸回文串的中心点
如下图所示,画的丑别在意 ,蓝色线表示虚拟的回文串,所以就有下面的递推式。
但是这样还不够,如果正好
p
[
i
]
p[i]
p[i]取了
m
s
−
i
ms-i
ms−i的值,则需要继续左右延伸,并更新答案,
m
s
ms
ms等。
i
f
(
m
s
>
i
)
p
[
i
]
=
m
i
n
(
p
[
2
∗
i
d
−
i
]
,
m
s
−
i
)
;
e
l
s
e
p
[
i
]
=
1
;
if\ (ms>i)\ p[i]=min(p[2*id-i],ms-i);else\ p[i]=1;
if (ms>i) p[i]=min(p[2∗id−i],ms−i);else p[i]=1;
其中,由规律可得,起点为
i
−
p
[
i
]
2
\frac{i-p[i]}{2}
2i−p[i],真实长度为
p
[
i
]
−
1
p[i]-1
p[i]−1。
M
a
n
a
c
h
e
r
Manacher
Manacher枫版
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#define fo(i,j,k) for (int i=j;i<=k;i++)
#define N 100005
using namespace std;
int p[N],n;
string s;
void solve(string s){
string x="$#";
int ans=0,len=0,ms=0,id=0;
for (int i=0;i<s.size();i++) x=x+s[i]+"#";
for (int i=0;i<x.size();i++){
if (ms>i) p[i]=min(p[2\*id-i],ms-i);else p[i]=1;
while (x[i+p[i]]==x[i-p[i]]) p[i]++;
if (ms<i+p[i]){
ms=i+p[i];
id=i;
}
if (len<p[i]){
len=p[i];
ans=i;
}
}
cout<<s.substr((ans-len)/2,len-1)<<endl;
}
int main(){
//freopen("xx.in","r",stdin);
cin>>n;
for (int i=1;i<=n;i++){
cin>>s;
solve(s);
}
return 0;
}
奇丑的暴力
c
h
a
r
char
char枫版
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,j,k) for (int i=j;i<=k;i++)
#define N 100005
using namespace std;
int n,st,ans;
char c[N];
void up(int x,int y){ //用来更新答案的
if ((x>ans)||((x==ans)&&(y<st))){
st=y;
ans=x;
}
}
int main(){
// freopen("xx.in","r",stdin);
scanf("%d",&n);
int x,l,k;
fo(i,1,n){
ans=0;st=0;
scanf("%s",c+1);
l=strlen(c+1);
fo(j,1,l){ //ans是最大长度,st是起点位置,k是半径
k=1;
while ((j-k>=1)&&(j+k<=l)&&(c[j-k]==c[j+k])) k++; //奇数长度
up(k\*2-1,j-k+1);
k=0;
while ((j-k>=1)&&(j+k+1<=l)&&(c[j-k]==c[j+k+1])) k++;//偶数长度
up(k\*2,j-k+1);
}
fo(i,st,ans+st-1) printf("%c",c[i]);
printf("\n");
}
return 0;
}
暴力冰版
#include<cstdio>
#include<cstring>
const int maxn = 1e4 + 5;
char s1[maxn], s2[maxn \* 2];
int n1, n2;
int find(int pos, int &ans) {
int i, j;
if (s2[pos] != '#') ++ans;
for (i = pos - 1, j = pos + 1; i >= 0 && j < n2; --i, ++j) {
if (s2[i] != s2[j]) return i + 1;
if (s2[i] != '#') ans += 2;
}
return i + 1;
}
int main() {
int t, i, j, tpos, tans, pos, ans;
scanf("%d", &t);
while (t--) {
pos = 0, ans = 1;
scanf("%s", s1);
n1 = strlen(s1);
n2 = n1 \* 2 + 1;
for (i = j = 0; i < n2; ++i) {
if (i & 1) s2[i] = s1[j++];
else s2[i] = '#';
} // 插入'#', 字符串长度为奇数, 避免分类讨论
s2[n2] = '\0';
for (i = 1; i < n2 - 1; ++i) { // 枚举回文串中点, 左右两边逐位比较
tans = 0;
tpos = find(i, tans);
if (tans > ans) pos = tpos, ans = tans;
}
for (i = pos; ans; ++i) {
if (s2[i] == '#') continue;
--ans; printf("%c", s2[i]);
}
printf("\n");
}
return 0;
}
Problem D 字符串比较
这题这么水,相信大家都AK了
题意:给定三个字符串,按字典序单调不下降排列。
丑到没朋友,丑到单身,丑到自闭,丑到想死,丑到不能再丑的的考试枫版
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define fo(i,j,k) for (int i=j;i<=k;i++)
#define N 100005
using namespace std;
int n,st,ans;
char c1[N],c2[N],c3[N];
void s(char (&a)[N],char (&b)[N]){
char t[N];
strcpy(t,a);
strcpy(a,b);
strcpy(b,t);
}
int main(){
// freopen("xx.in","r",stdin);
scanf("%s%s%s",c1,c2,c3);
if (strcmp(c1,c2)>0) s(c1,c2);
if (strcmp(c1,c3)>0) s(c1,c3);
if (strcmp(c2,c3)>0) s(c2,c3);
cout<<c1<<endl<<c2<<endl<<c3;
return 0;
}
重新做人指针交换枫版
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define fo(i,j,k) for (int i=j;i<=k;i++)
#define N 100005
using namespace std;
int n,st,ans;
char c1[N],c2[N],c3[N];
int main(){
freopen("xx.in","r",stdin);
scanf("%s%s%s",c1,c2,c3);
char \*a,\*b,\*c;
a=c1;b=c2;c=c3;
if (strcmp(a,b)>0) swap(a,b);
if (strcmp(a,c)>0) swap(a,c);
if (strcmp(b,c)>0) swap(b,c);
cout<<a<<endl<<b<<endl<<c;
return 0;
}
冰版
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main() {
string str[3];
for (int i = 0; i < 3; ++i) cin >> str[i];
sort(str, str + 3);
for (int i = 0; i < 3; ++i) cout << str[i] << endl;
return 0;
}
Problem E 最小公倍数
这题这么水,相信大家都AK了
题意:求两个数最小公倍数
敲黑板!
l
c
m
(
a
,
b
)
=
a
∗
b
g
c
d
(
a
,
b
)
lcm(a,b)=\frac{a*b}{gcd(a,b)}
lcm(a,b)=gcd(a,b)a∗b记几试着整理整理,证明一下,要记住的。
g
c
d
gcd
gcd用辗转相除法求即可。
枫版
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define fo(i,j,k) for (int i=j;i<=k;i++)
#define N 100005
using namespace std;
int n,st,ans,a,b,c;
int main(){
//freopen("xx.in","r",stdin);
scanf("%d%d",&a,&b);
c=\_\_gcd(a,b); //偷了个小懒,用内置gcd
printf("Least common multiple: %d",a\*b/c);
return 0;
}
冰版
#include<cstdio>
int gcd(int a, int b) { // 辗转相除法
return b ? gcd(b, a % b) : a;
}
int lcm(int a, int b) {
return a / gcd(a, b) \* b;
}
int main() {
int a, b;
scanf("%d%d", &a, &b);
printf("Least common multiple: %d", lcm(a, b));
return 0;
}
Problem F 奖学金测评
这题这么水,相信大家都AK了
题意 现在已经得到了每位同学的姓名,德育分,智育分和文体分,想请你继续完成这个程序,利用这些数据得出每位同学的最终分数和全班的排名。 每位同学的最终分数为各项的加权得分之和,加权得分即为该项得分乘以相应的权值。德育的权值为30%×3,智育的权值为40%×3,文体的权值为30%×3,(结果保留了一位小数)。
没办法,用
s
t
r
u
c
t
struct
struct吧,快捷好省,另外
d
a
l
a
o
最后前端到底应该怎么学才好?
如果你打算靠自己摸索自学,那么你首先要了解学习前端的基本大纲,这是你将要学习的主要内容,理解以及掌握好这些内容,便可以找到一份初级的前端开发工作。你还需要有一套完整的前端学习教程,作为初学者最好的方式就是看视频教程学习,初学者容易理解接受。
不要选择买书学习,这样的方式没有几个人能学会,基本都是看不下去书,也看不懂书。如果喜欢看书的学弟,可以买一些经典的书籍作为辅助即可,主要还是以看教程为主。每天抽出固定几个小时学习,做好长期学习的准备。学习编程并不是每天光看视频,你学习编程最重要的目的是为了编写软件产品,提供给大众使用,所以用手写出代码实现功能才是我们要做的事情。