言尽于此,完结
无论是一个初级的 coder,高级的程序员,还是顶级的系统架构师,应该都有深刻的领会到设计模式的重要性。
- 第一,设计模式能让专业人之间交流方便,如下:
程序员A:这里我用了XXX设计模式
程序员B:那我大致了解你程序的设计思路了
- 第二,易维护
项目经理:今天客户有这样一个需求…
程序员:明白了,这里我使用了XXX设计模式,所以改起来很快
- 第三,设计模式是编程经验的总结
程序员A:B,你怎么想到要这样去构建你的代码
程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题
- 第四,学习设计模式并不是必须的
程序员A:B,你这段代码使用的是XXX设计模式对吗?
程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的
从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!
搜集费时费力,能看到此处的都是真爱!
这里举例来说明我们用排好序的下标来代替数,这样控制住数的范围,且结果一样:
我们可以看到 第一个数 4,4后面比其小的数 还是有 3 个;
====================================================================
/**
思路:这个题并没有给出 输入的数字的范围 那就无法直接用 求逆序对的方法来求
因为会出现段错误(因为输入的数 可能大于 500000)
但是我们可以将输入的数进行转换,将他们先进行排序,将他们的下标作为他们的
代替,这样我们就控制住输入数字的范围了,这个题也已经明确指出了输入数字
不重复,所以我们可以大胆的用map,来记录他们的排序
*/
#include<bits/stdc++.h>
using namespace std;
int c[100005];
int lowbit(int x){
return x&(-x);
}
//单点更新
void update(int x,int y,int n){
while(x <= n){
c[x] = c[x] + y;
x = x + lowbit(x);
}
}
//求取前缀和
int getSum(int pos){
int sum = 0;
while(pos > 0){
sum += c[pos];
pos = pos - lowbit(pos);
}
return sum;
}
int main(){
int a[100005];
vector v1,v2,v3;
map<int,int>m;
int N;
memset(a,0,sizeof(a));
memset(c,0,sizeof©);
cin >> N;
for(int i = 0; i < N; i++){
int temp;
cin >> temp;
a[i] = temp;
v1.push_back(temp);
}
sort(v1.begin(),v1.end());
for(int i = 0; i < N; i++){
m[v1[i]] = i + 1;
}
for(int i = N - 1; i >= 0; i–){
int num = m[a[i]];
update(num,1,100005);
//这里求的是getSum(temp) 表示的是前面比 temp小的个数其中是包含temp本身的
int temp = getSum(num) - 1;
v2.push_back(temp);
}
for(int i = N-1; i >= 0; i–){
if(i == N - 1){
cout << v2[i];
}else{
cout << ’ ’ << v2[i];
}
}
}
========================================================================
(1):图示:
(2):相关的介绍
相关知识介绍:
1.理解图 A[i]:表示的是正常的数组
C[i]:表示的是区间的和
eg: c[1] =A[1]
c[2] = A[1] + A[2]
c[6] = A[5] + A[6]
2.那么如何表示C[i] 中 i表示的个数呢 这时候要用到lowbit(i),
lowbit(i) = i & (-i)
eg:lowbit(6) = 2
lowbit(4) = 4
3.i + lowbit[i]:表示其父亲结点的下标
eg:6 + lowbit(6) = 8
i - lowbit(i):表示其左边管辖区域的下标
eg:6 - lowbit(6) = 4
4.相关的函数
(1):求取lowbit(i)
int lowbit (int i){
return i & (-i);
}
(2):更新单点的值,就是如果你给区间内的某个值增加一定的数,那么其父节点
也会增加相应的值
eg: A[1]比以前大了,那么C[1]也要比以前的大,他的父节点C[2],
也要跟着变大,那么的话,c[2]的父节点也要跟着变大
void update(int x,int y,int n){//参数:表示在x位置增加了y 数组长度为n
while(x <= n){
c[x] = c[x] + y;
x = x + lowbit(x);//求取父节点
}
}
(3):求前缀和
eg:求取前6个数的和
sum[6] = A[1] + A[2] + A[3]+ A[4]+ A[5] + A[6]
因为:C[6] = A[5] + A[6]
C[4] = A[1]+A[2]+A[3]+A[4]
那么也就是sum[6] = C[6] + C[4]
int getSum(int pos){
int sum = 0;
while(pos > 0){
sum += C[pos]
pos = pos - lowbit[pos]
}
return sum;
}
题目:求出某区间每一个数的和
输入格式
第一行包含两个正整数n,m,分别表示该数列数字的个数和
操作的总个数
第二行包含n个用空格分隔的整数,其中第i个数字表示数
列第i项的初始值
接下来m行每行包含3个整数,表示一个操作,具体如下
·1 x k含义:将第x个数加上k
·2 x y含义:输出区间{x,y}内每个数的和
输出格式
输出包含若干行整数,即为所有操作2的结果。
输入样例: 5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4
输出:14
16
/**
题目:求出某区间每一个数的和
输入格式
第一行包含两个正整数n,m,分别表示该数列数字的个数和
操作的总个数
第二行包含n个用空格分隔的整数,其中第i个数字表示数
列第i项的初始值
接下来m行每行包含3个整数,表示一个操作,具体如下
·1 x k含义:将第x个数加上k
·2 x y含义:输出区间{x,y}内每个数的和
输出格式
输出包含若干行整数,即为所有操作2的结果。
输入样例: 5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4
输出:14
16
相关知识介绍:
1.理解图 A[i]:表示的是正常的数组
C[i]:表示的是区间的和
eg: c[1] =A[1]
c[2] = A[1] + A[2]
c[6] = A[5] + A[6]
2.那么如何表示C[i] 中 i表示的个数呢 这时候要用到lowbit(i),
lowbit(i) = i & (-i)
eg:lowbit(6) = 2
lowbit(4) = 4
3.i + lowbit[i]:表示其父亲结点的下标
eg:6 + lowbit(6) = 8
i - lowbit(i):表示其左边管辖区域的下标
eg:6 - lowbit(6) = 4
4.相关的函数
(1):求取lowbit(i)
int lowbit (int i){
return i & (-i);
}
(2):更新单点的值,就是如果你给区间内的某个值增加一定的数,那么其父节点
也会增加相应的值
eg: A[1]比以前大了,那么C[1]也要比以前的大,他的父节点C[2],
也要跟着变大,那么的话,c[2]的父节点也要跟着变大
void update(int x,int y,int n){//参数:表示在x位置增加了y 数组长度为n
while(x <= n){
c[x] = c[x] + y;
x = x + lowbit(x);//求取父节点
}
}
(3):求前缀和
eg:求取前6个数的和
sum[6] = A[1] + A[2] + A[3]+ A[4]+ A[5] + A[6]
因为:C[6] = A[5] + A[6]
C[4] = A[1]+A[2]+A[3]+A[4]
那么也就是sum[6] = C[6] + C[4]
int getSum(int pos){
int sum = 0;
while(pos > 0){
sum += C[pos]
pos = pos - lowbit[pos]
}
return sum;
}
*/
#include<bits/stdc++.h>
using namespace std;
int c[1000] = {0};
int lowbit(int x){
return x&(-x);
}
//更新单节点
void update(int x,int y,int n){
while(x <= n){
c[x] = c[x] + y;
x = x + lowbit(x);
}
}
//求前缀和
int getSum(int pos){
int sum = 0;
while(pos > 0){
sum += c[pos];
pos = pos - lowbit(pos);
}
return sum;
}
int main(){
int N,M;
int a[1000];
memset(a,0,sizeof(a));
cin >> N >> M;
for(int i = 1; i <= N; i++){
cin >>a[i];
//这里就是往C[i]中赋值的操作,因为初始的a[i]中的值均为0,故可以开始更新
update(i,a[i],N);
}
for(int i = 0; i < M; i++){
int operation,num1,num2;
cin >> operation >> num1 >> num2;
if(operation == 1){
update(num1,num2,N);
}else if(operation == 2){
cout << getSum(num2) - getSum(num1-1) << endl;
}else{
cout << “您的输入有误!!”;
}
}
//测试数据
// for(int i = 1; i <= N; i++){
// cout << c[i] << ’ ';
// }
// cout << a[99];
}
/**
·1 x k含义:将第x个数加上k
·2 x y含义:输出区间{x,y}内每个数的和
输出格式
输出包含若干行整数,即为所有操作2的结果。
输入样例: 5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4
输出:14
16
*/
//5 5
//1 5 4 2 3
//1 1 3
//2 2 5
//1 3 -1
//1 4 2
//2 1 4
何为逆序对:
什么是逆序对
设A为一个有n个数字的有序集(>1),其中所有数字各不相同。如果存在正整数i,j
使得1<=i<j<=n而且A[i]>A[j],则<A[i],A[j]>这个有序对称为A的一个逆序对,也称作逆序数。例如
数组(3 1 4 5 2)的逆序对有(3,1)(32)(42)(5,2),共4个
思路:输入的N个数 3 1 4 5 2
每次输入的值都在 A[i](i = 输入的值) 对应的位置 A[3] = 1,A[1] = 1;
其中A[] ,C[],初始化均为0,每次a[i]变化对应的更新C[i]的值
那么前面比其大的数的个数 = i - (前面比其小的个数)
= i - getSum(a[i])
/**
何为逆序对:
什么是逆序对
设A为一个有n个数字的有序集(>1),其中所有数字各不相同。如果存在正整数i,j
使得1<=i<j<=n而且A[i]>A[j],则<A[i],A[j]>这个有序对称为A的一个逆序对,也称作逆序数。例如
数组(3 1 4 5 2)的逆序对有(3,1)(32)(42)(5,2),共4个
思路:输入的N个数 3 1 4 5 2
每次输入的值都在 A[i](i = 输入的值) 对应的位置 A[3] = 1,A[1] = 1;
其中A[] ,C[],初始化均为0,每次a[i]变化对应的更新C[i]的值
那么前面比其大的数的个数 = i - (前面比其小的个数)
= i - getSum(a[i])
*/
#include<bits/stdc++.h>
using namespace std;
int c[1000];
int lowbit(int x){
return x&(-x);
}
//单点更新
void update(int x,int y,int n){
while(x <= n){
c[x] = c[x] + y;
x = x + lowbit(x);
}
}
//求取前缀和
int getSum(int pos){
int sum = 0;
while(pos > 0){
sum += c[pos];
pos = pos - lowbit(pos);
}
return sum;
}
int main(){
int a[1000],b[1000];
int N;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof©);
cin >> N;
for(int i = 1; i <= N; i++){
int temp;
cin >> temp;
a[temp] = 1;
结局:总结+分享
看完美团、字节、腾讯这三家的一二三面试问题,是不是感觉问的特别多,可能咱们真的又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。
开篇有提及我可是足足背下了Java互联网工程师面试1000题,多少还是有点用的呢,换汤不换药,不管面试官怎么问你,抓住本质即可!能读到此处的都是真爱
- Java互联网工程师面试1000题
而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的 《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。
- 程序员代码面试指南–IT名企算法与数据结构题目最优解
- 其余像设计模式,建议可以看看下面这4份PDF(已经整理)
- 更多的Java面试学习笔记如下,关于面试这一块,我额外细分出Java基础-中级-高级开发的面试+解析,以及调优笔记等等等。。。
以上所提及的全部Java面试学习的PDF及笔记,如若皆是你所需要的,那么都可发送给你!
b[1000];
int N;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof©);
cin >> N;
for(int i = 1; i <= N; i++){
int temp;
cin >> temp;
a[temp] = 1;
结局:总结+分享
看完美团、字节、腾讯这三家的一二三面试问题,是不是感觉问的特别多,可能咱们真的又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。
开篇有提及我可是足足背下了Java互联网工程师面试1000题,多少还是有点用的呢,换汤不换药,不管面试官怎么问你,抓住本质即可!能读到此处的都是真爱
- Java互联网工程师面试1000题
[外链图片转存中…(img-r2tmKdbc-1715760109456)]
而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的 《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。
- 程序员代码面试指南–IT名企算法与数据结构题目最优解
[外链图片转存中…(img-M6jwDBly-1715760109456)]
- 其余像设计模式,建议可以看看下面这4份PDF(已经整理)
[外链图片转存中…(img-9GvFpLyA-1715760109457)]
- 更多的Java面试学习笔记如下,关于面试这一块,我额外细分出Java基础-中级-高级开发的面试+解析,以及调优笔记等等等。。。
[外链图片转存中…(img-XTJjCctz-1715760109457)]
以上所提及的全部Java面试学习的PDF及笔记,如若皆是你所需要的,那么都可发送给你!