1010 Lehmer Code (35 分)(思路+详解+树状数组的学习+逆序对+map+vector) 超级详细 Come baby!!!

言尽于此,完结

无论是一个初级的 coder,高级的程序员,还是顶级的系统架构师,应该都有深刻的领会到设计模式的重要性。

  • 第一,设计模式能让专业人之间交流方便,如下:

程序员A:这里我用了XXX设计模式

程序员B:那我大致了解你程序的设计思路了

  • 第二,易维护

项目经理:今天客户有这样一个需求…

程序员:明白了,这里我使用了XXX设计模式,所以改起来很快

  • 第三,设计模式是编程经验的总结

程序员A:B,你怎么想到要这样去构建你的代码

程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题

  • 第四,学习设计模式并不是必须的

程序员A:B,你这段代码使用的是XXX设计模式对吗?

程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的

image

从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!

image

搜集费时费力,能看到此处的都是真爱!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

这里举例来说明我们用排好序的下标来代替数,这样控制住数的范围,且结果一样:

在这里插入图片描述

我们可以看到 第一个数 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:树状数组


(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;

}

2:例题求取区间和


题目:求出某区间每一个数的和

输入格式

第一行包含两个正整数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

3:求逆序对


何为逆序对:

什么是逆序对

设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题

image.png

而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的 《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。

  • 程序员代码面试指南–IT名企算法与数据结构题目最优解

image.png

  • 其余像设计模式,建议可以看看下面这4份PDF(已经整理)

image.png

  • 更多的Java面试学习笔记如下,关于面试这一块,我额外细分出Java基础-中级-高级开发的面试+解析,以及调优笔记等等等。。。

image.png

以上所提及的全部Java面试学习的PDF及笔记,如若皆是你所需要的,那么都可发送给你!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

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及笔记,如若皆是你所需要的,那么都可发送给你!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值