这是桑榆的笔记

笔记本

桑榆的积累

数据库软件(MySQL)

08. 基础-SQL-DDL-数据类型及案例_哔哩哔哩_bilibili

数据库DataBase(DB)(相当于备忘录):储存数据

数据库管理系统(操纵和管理数据库的大型软件,比如MySQL)

SQL(structed query language):操作关系型数据库的语言

MySQL(免费软件,写数据库用,就像我现在写markdown用Typora一样)

最终都是用的SQL操作,所以软件无所谓的,习惯那个用哪个

MySQL

  1. 社区版(免费)
  2. 商业版(给钱)

关系型数据库(RDBMS):建立在关系模型上,由==多张连接的二维表==组成的数据库!

image-20250423170326397

仅展示两张,这两张的关联在dept_id与id/name里!

非关系型数据库就是不按表储存

安装了MySQL就相当于有了MySQL服务器,就可以将客户端与DBMS连接

SQL语法:(和C++类似)

  1. 对缩进和空格要求不严格
  2. 分号结尾
  3. ==对大小写不严格,都可以==
  4. 注释
    1. //
    2. /* */

DDL(data defination language): 定义对象(搭建大致框架)

DML (data manipulation language): 增 删 改

DQL (data quary language): 查询

DCL (data control language): 权限问题

DDL

查询所有数据库

1
SHOW DATABATES;

查询当前数据库

1
SELECT DATABASE();//记不清楚自己的数据库了,记得加括号,这是个函数

创建数据库

1
2
CREATE DATABASE 数据库名;
CREATE DATABASE IF NOT EXISTS 数据库名;

删除数据库

1
DROP DATABASE 数据库名;//drop

使用数据库

1
USE 数据库名;//相当于切换到这个数据库下,和cd切换一样

查询当前数据库所有表

1
SHOW TABLES;

查询表结构

1
DESC 表名;//description描述

查询指定表的建表语句

1
SHOW CREATE TEBLE 表名;//这个比desc多展示一些东西!!!		

创建表(函数)//==切记不要在系统库里面用,创建之前一定要USE到自己的数据库==

1
2
3
4
CREATE TABLE 表名//相当于类或结构体
(名 类型 comment "这就是在这里面的对名的注释";
名 类型;
名 类型);//这些都是表头上的内容,而成员信息是另一个东西!!!!,切记不能是空表
image-20250423181906843

int ,float,double

image-20250423182245898

char//固定,但性能好,如果不写长度,默认为1

varchar//可变,性能差

image-20250423182632724

date,time

image-20250423182922951

1
2
3
4
5
6
7
8
9
10
11
12
CREATE DATABASE;
USE DATABASE;
CREATE TABLE INFORMATION
(
编号 int,
员工工号 varchar(10),
员工姓名 VARCHAR(10),
性别 CHAR(1),
年龄 TINYINT,
身份证号 CHAR(18),
入职时间 DATA
)

添加

1
ALTER TABLE 表名ADD 字段名 类型(长度) COMMENT 注释;//alter是改变!

案例

为emp表增加一个新字段nickname,类型为varchar(20)

修改

1
2
3
4
//修改数据类型
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);//modify也是修改
//修改字段名和数据类型
ALTER TABLE 表名 CHANGE 旧名 新名 类型(长度) COMMENT 注释;

案例

将emp表的nickname改成username,类型为varchar(30)

删除字段

1
ALTER TABLE 表名 DROP 字段名;

案例

将emp表的username删除

修改表名

1
ALTER TABLE 表名 RENAME TO 新表名;

案例

将emp表的表名修改为employee

删除表

1
DROP TABLE IF EXISTS 表名;//IF EXISTS可以不加

删除指定表,并重新创建该表

1
TRUNCATE TABLE 表名;//truncate删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//内容回顾DDL
SHOW DATABASES;
CREAT DATABASE 数据库名;
USE 数据库名;
SELECT DATABASE();
DROP DATABASE 数据库名;

SHOW TABLES;
CREAT TABLE 表名
();//切记表名得和内部元素一同创建,不然就是一个空表
DESC 表名;
SHOW CREAT TABLE 表名;//有的时候你得说清楚是什么表,所以得加表名,而CREAT对象很多
//所以有的时候又得说清楚CREAT DATABASE/TABLE
ALTER TABLE ADD/DROP/CHANGE/MODIFY/RENAME TO
DROP TABLE 表名;

==但是这样子在命令行里操作不直观,所以可以可视化处理,这样子可以清晰且提高效率==

图形化界面

Sqlyog/==DataGrip==/Navicat

DataGrip里创建数据库schema和database一样

image-20250424110243582

DML

增加(INSERT)

修改(UPDATE)

删除(DELETE)

添加数据

  1. 给指定字段添加数据

    1
    2
    3
    4
    5
    6
    7
    INSERT INTO 表名 (字段1,字段2,...)VALUES(值1,值2,....);
    //如果是给所有字段添加数据,那么就直接不写(字段1,字段2,...)
    //如果要批量添加:VALUES(值1,值2,....),(值1,值2,....),(值1,值2,....);
    //在value后添加”,“隔开。
    //*可不可以表示泛呢?好像没法。
    //实质上也是键值对,所以要对应
    //字符串和日期本质都是字符串,所以要放在引号里
  2. 修改数据

    1
    2
    UPDATE 表名 SET 字段名1=值1,字段名2=值2,... WHERE 条件;
    //没有条件就是修改整张表!!!所以修改一个那么就得加条件,别一个不小心把整张表都改了
  3. 删除数据

    1
    2
    3
    DELETE FROM 表名 WHERE 条件;
    //没有条件就是删除整张表的数据
    //DELETE不能只删除某一个字段的值(可以用update)
1
2
3
4
//内容回顾
INSERT INTO 表名 (字段1,字段2,...)VALUES(值1,值2,....);
UPDATE 表名 SET 字段名1=值1,字段名2=值2,... WHERE 条件;
DELETE FROM 表名 WHERE 条件;
DQL

SELECT

​ 字段列表

FROM

​ 表名列表

WHERE

​ 条件列表

GROUP BY

​ 分组字段列表

HAVING

​ 分组后条件列表

ORDER BY

​ 排序字段列表

LIMIT

​ 分页参数

  • 基本查询

  • 条件查询

  • 聚合函数

  • 分组查询

  • 排序查询

  • 分页查询

查询//返回的是一个表!按列返回

所有查询的本质就是

1
SELECT 字段列表 FROM 表名;
  1. 基本查询
1
2
3
4
5
//查询返回多个字段
SELECT 字段1 AS 别名1,字段2,字段3... FROM 表名;//AS可以省略
SELECT * FROM 表名;//*表泛,可以给字段设别名
//去除重复记录
SELECT DISTINCT 字段列表 FROM 表名;//DISTINCT就是个去重操作
  1. 条件查询//加WHERE实现

    1
    SELECT 字段列表 FROM 表名 WHERE 条件列表;

    image-20250423220056183

  2. 聚合函数(将一列数据作为一个整体,进行纵向计算)

    1
    SELECT 聚合函数(字段列表)FROM 表名;

    image-20250423221242907

PPT

因为要参加物理实验竞赛,所以我开始学习做PPT了,基本上参考了这些大佬的教程,也是做出来了一个看上去貌似还不错的PPT

PPT这样排版可太高级了_哔哩哔哩_bilibili

5分钟学会多种PPT结尾页设计排版_哔哩哔哩_bilibili

PPT目录而已 要这么卷嘛_哔哩哔哩_bilibili

PPT抽拉页设计你学会了吗_哔哩哔哩_bilibili

PPT封面多图如何排版_哔哩哔哩_bilibili

这不是特效,这是PPT光影片头!_哔哩哔哩_bilibili

用ppt制作圆环旋转,震撼真是太震撼了!_哔哩哔哩_bilibili

ppt视觉差效果,某台破千万播放,1分钟教会你!_哔哩哔哩_bilibili

ppt高级感云雾散开_哔哩哔哩_bilibili

【PPT教学|133】这个流动式动画太太赞了!_哔哩哔哩_bilibili

59秒学会PPT钟摆图片切换_哔哩哔哩_bilibili

PPT也意识流,灵感来源《沙丘-恐惧》(来取源文件)_哔哩哔哩_bilibili

PPT窗口文本交互动画设计教学_哔哩哔哩_bilibili

这个创意PPT过渡页被领导夸爆了!1分钟学会!_哔哩哔哩_bilibili

这个创意PPT过渡页被领导夸爆了!1分钟学会!_哔哩哔哩_bilibili

1分钟教会你PPT多图片轮播的极致!_哔哩哔哩_bilibili

[第37期] PPT教学——数字交错分割效果 (过渡页中的数字用上这种交错分割效果,让你的ppt卷起来!)_哔哩哔哩_bilibili

PPT过渡,竟能如此创意!_哔哩哔哩_bilibili

这不是PPT技术,是PPT魔术吧_哔哩哔哩_bilibili

纯色也能设计出高级感PPT_哔哩哔哩_bilibili

如何做出超高级的PPT动态镂空封面?_哔哩哔哩_bilibili

我也不想技惊全场,何况这只是我的PPT开场_哔哩哔哩_bilibili

https://www.bilibili.com/video/BV1cF411v7Ny/?spm_id_from=333.1391.0.0

超简单2步,就做出电影级的PPT_哔哩哔哩_bilibili

毛玻璃、悬停、缩放定位,这些元素加起来,就有了一个高级PPT_哔哩哔哩_bilibili

PPT表格还能这样玩?文字看不清,一垫就清晰!_哔哩哔哩_bilibili

PPT制作的丝滑过渡效果,有点高级,是不舍得教会别人的那种_哔哩哔哩_bilibili

PPT制作封面页设计_哔哩哔哩_bilibili

屎盆子镶金边ppt教学_哔哩哔哩_bilibili

教你两种又快又好用的方法制作PPT笔刷效果_哔哩哔哩_bilibili

怎样让 PPT 立起来?_哔哩哔哩_bilibili

【教程】PPT制作教程:快速提升幻灯片质量的方法_哔哩哔哩_bilibili

千万别再这么傻傻的做PPT人物介绍了!用这一招,高级感立马拉满!_哔哩哔哩_bilibili

PPT蒙版的99个进阶用法_哔哩哔哩_bilibili

超实用的PPT小技巧,飘动页面_哔哩哔哩_bilibili

不敢相信!外网这个PPT视差动画,让图片变3D版了【旁门左道】_哔哩哔哩_bilibili

同事竟一分钟做出PPT闭幕式结尾!领导说太绝了!_哔哩哔哩_bilibili

【ppt分享】把ppt做成你买不起样子_哔哩哔哩_bilibili

ppt分屏视觉差,绝对惊艳你!_哔哩哔哩_bilibili

1分钟教会你秒杀全场的旋转开场PPT!_哔哩哔哩_bilibili

1分钟教会你这个大气2025开场PPT!_哔哩哔哩_bilibili

电影级别的PPT动画开场_哔哩哔哩_bilibili

PPT图表侧滑轮播教程_哔哩哔哩_bilibili

让人眼前一亮的PPT多图展示效果_哔哩哔哩_bilibili

ppt简单制作高端效果_哔哩哔哩_bilibili

用这个PPT技能真的很卷,让你的演示效果立马拉满!_哔哩哔哩_bilibili

当我拿出这个PPT结尾,阁下又该如何应对?_哔哩哔哩_bilibili

PPT结尾页别再用谢谢观看了_哔哩哔哩_bilibili

谁懂啊!这个PPT图片切换效果真的太太太高级了!领导夸爆了!_哔哩哔哩_bilibili

PPT电影级结尾,诸位,看好咯,这样做PPT一定让你的领导赞不绝口!!_哔哩哔哩_bilibili

做PPT千万别太“规矩”,学会这招,让PPT立马飞起来!_哔哩哔哩_bilibili

后来我做过很多PPT,但只有这一个让我念念不忘_哔哩哔哩_bilibili

强中自有强中手,一山更比一山高,诸位,这个PPT,瞧好了!_哔哩哔哩_bilibili

大道至简返璞归真,牛皮的PPT从不需要多余的点缀!_哔哩哔哩_bilibili

只需多做一步,就能轻松拿捏高级感PPT_哔哩哔哩_bilibili

高级的开场动画只需要简单的操作_哔哩哔哩_bilibili

如果你以为这是剪辑软件做的,我带你认识真正的PPT_哔哩哔哩_bilibili

谁懂!这样的ppt旋转切换效果真的太太绝了!_哔哩哔哩_bilibili

秒杀全场同事的超高级旋转开场PPT动画!_哔哩哔哩_bilibili

让领导眼前一亮的PPT目录页!太高级了!_哔哩哔哩_bilibili

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
clc; clear; close all;



%% 基本参数设置

lambda_all = [450e-9, 550e-9, 650e-9]; % 多波长:蓝、绿、红

colors = [0 0 1; 0 1 0; 1 0 0]; % RGB颜色

f = 20e-3; % 透镜焦距

R = 100e-3; % 曲率半径(调大,更明显)

lens_z = 0; % 透镜位置

screen_z = 25e-3; % 屏幕位置



num_frames = 50; % 动画帧数

num_rays = 30; % 光线数量

theta = linspace(-pi/12, pi/12, num_rays); % 光线角度



%% 视频设置

v = VideoWriter('newton_rings_full_fixed.avi');

v.FrameRate = 15;

open(v);



%% 设置固定大小的图窗

fig = figure('Color','w', 'Position', [100, 100, 800, 600]);



%% 动画主循环

for t = 1:num_frames



clf;

hold on; axis equal; grid on;

xlabel('X (m)'); ylabel('Y (m)'); zlabel('Z (m)');

xlim([-0.02 0.02]); ylim([-0.02 0.02]); zlim([0 0.03]);

view([0 90]); % 俯视(XY 平面)



title('多波长牛顿环光线传播');



%% 光线追踪(多波长)

for w = 1:length(lambda_all)

lambda = lambda_all(w);

color = colors(w, :);

for i = 1:num_rays

angle = theta(i);

% 初始点和方向

x0 = 0; y0 = 0; z0 = 0;

vx1 = sin(angle); vy1 = 0; vz1 = cos(angle);

t1 = (lens_z - z0) / vz1;

x1 = x0 + vx1 * t1;

y1 = y0 + vy1 * t1;

z1 = lens_z;



% 折射计算

n1 = 1.0; n2 = 1.5;

theta2 = asin(n1/n2 * sin(angle));

vx2 = sin(theta2); vy2 = 0; vz2 = cos(theta2);

t2 = (screen_z - lens_z) / vz2;

x2 = x1 + vx2 * t2;

y2 = y1 + vy2 * t2;

z2 = screen_z;



% 动态比例

scale1 = min(1, t / num_frames);

scale2 = max(0, t/num_frames - 0.5) * 2;



% 绘制第一段(空气中)

xa = x0 + vx1 * t1 * scale1;

ya = y0 + vy1 * t1 * scale1;

za = z0 + vz1 * t1 * scale1;

plot3([x0 xa], [y0 ya], [z0 za], 'Color', color, 'LineWidth', 1.2);



% 绘制第二段(透镜中)

if t > num_frames/2

xb = x1 + vx2 * t2 * scale2;

yb = y1 + vy2 * t2 * scale2;

zb = z1 + vz2 * t2 * scale2;

plot3([x1 xb], [y1 yb], [z1 zb], 'Color', color * 0.8 + 0.2, ...

'LineStyle','--', 'LineWidth', 1);

end

end

end



%% 牛顿环绘制(增强可视化)

num_rings = 20;

for w = 1:length(lambda_all)

lambda = lambda_all(w);

color = colors(w,:);

bright_color = color * 0.8 + 0.2; % 提亮颜色

for n = 1:num_rings

r_n = sqrt(n * lambda * R); % Newton ring 半径

theta_ring = linspace(0, 2*pi, 200);

x_ring = r_n * cos(theta_ring);

y_ring = r_n * sin(theta_ring);

z_ring = (screen_z + 1e-4) * ones(size(x_ring)); % 抬高,避免遮挡



fill3(x_ring, y_ring, z_ring, bright_color, ...

'FaceAlpha', 0.15 + 0.02*w, ...

'EdgeColor', bright_color * 0.9, 'LineWidth', 0.5);

end

end



%% 写入帧,强制统一为 800x600 尺寸

raw_frame = getframe(fig);

resized_frame = imresize(raw_frame.cdata, [600 800]); % 高度 × 宽度

writeVideo(v, im2frame(resized_frame));

end



close(v);

img

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
clc; clear; close all;



%% 基本参数设置

lambda = 550e-9; % 单色光:绿光

color = [1 1 1]; % 白色光线

f = 20e-3; % 透镜焦距

R = 10e-3; % 曲率半径

lens_z = 0; % 透镜位置

screen_z = 25e-3; % 屏幕位置



num_frames = 50; % 动画帧数

num_rays = 30; % 光线数量

theta = linspace(-pi/12, pi/12, num_rays); % 光线角度



%% 视频设置

v = VideoWriter('newton_rings_white_on_black.avi');

v.FrameRate = 15;

open(v);



%% 设置固定大小的图窗

fig = figure('Color','k', 'Position', [100, 100, 800, 600]);



%% 动画主循环

for t = 1:num_frames

clf;

hold on; axis equal; grid on;

xlabel('X (m)', 'Color', 'w'); ylabel('Y (m)', 'Color', 'w'); zlabel('Z (m)', 'Color', 'w');

xlim([-0.01 0.01]); ylim([-0.01 0.01]); zlim([-0.005 0.03]);

set(gca, 'Color', 'k', 'XColor', 'w', 'YColor', 'w', 'ZColor', 'w');

view(2); % 改为俯视图(更容易看出环)



title('白光牛顿环', 'Color', 'w');



%% 光线追踪

for i = 1:num_rays

angle = theta(i);

x0 = 0; y0 = 0; z0 = -5e-3;

vx1 = sin(angle); vy1 = 0; vz1 = cos(angle);

t1 = (lens_z - z0) / vz1;

x1 = x0 + vx1 * t1;

y1 = y0 + vy1 * t1;

z1 = lens_z;



n1 = 1.0; n2 = 1.5;

theta2 = asin(n1/n2 * sin(angle));

vx2 = sin(theta2); vy2 = 0; vz2 = cos(theta2);

t2 = (screen_z - lens_z) / vz2;

x2 = x1 + vx2 * t2;

y2 = y1 + vy2 * t2;

z2 = screen_z;



scale1 = min(1, t / num_frames);

scale2 = max(0, t/num_frames - 0.5) * 2;



xa = x0 + vx1 * t1 * scale1;

ya = y0 + vy1 * t1 * scale1;

za = z0 + vz1 * t1 * scale1;

plot3([x0 xa], [y0 ya], [z0 za], 'Color', color, 'LineWidth', 1.2);



if t > num_frames/2

xb = x1 + vx2 * t2 * scale2;

yb = y1 + vy2 * t2 * scale2;

zb = z1 + vz2 * t2 * scale2;

plot3([x1 xb], [y1 yb], [z1 zb], 'Color', color * 0.8 + 0.2, ...

'LineStyle','--', 'LineWidth', 1);

end

end



%% 屏幕贴图牛顿环图案(灰度)

[xg, yg] = meshgrid(linspace(-0.002, 0.002, 600)); % 缩小范围

rg = sqrt(xg.^2 + yg.^2);

intensity = cos(pi * rg.^2 / (lambda * R)).^2; % 经典牛顿环表达式

zg = screen_z * ones(size(xg));

surf(xg, yg, zg, intensity, 'EdgeColor', 'none');

colormap(gray);



%% 写入帧

raw_frame = getframe(fig);

resized_frame = imresize(raw_frame.cdata, [600 800]);

writeVideo(v, im2frame(resized_frame));

end



close(v);

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
clc; clear; close all;

%% 基本参数设置
lambda = 550e-9; % 中心波长
f = 20e-3; % 透镜焦距
R = 10e-3; % 曲率半径
lens_z = 0; % 透镜位置
screen_z = 25e-3; % 屏幕位置

num_frames = 50; % 动画帧数
num_rays = 30; % 光线数量
theta = linspace(-pi/12, pi/12, num_rays); % 光线角度

%% 视频设置
v = VideoWriter('newton_rings_color_dynamic.avi');
v.FrameRate = 15;
open(v);

%% 设置固定大小的图窗
fig = figure('Color','k', 'Position', [100, 100, 800, 600]);

%% 动画主循环
for t = 1:num_frames
clf;
hold on; axis equal; grid on;
xlabel('X (m)', 'Color', 'w'); ylabel('Y (m)', 'Color', 'w'); zlabel('Z (m)', 'Color', 'w');
xlim([-0.005 0.005]); ylim([-0.005 0.005]); zlim([-0.005 0.03]);
set(gca, 'Color', 'k', 'XColor', 'w', 'YColor', 'w', 'ZColor', 'w');
view(3); % 三维视角

title('彩色动态三维牛顿环', 'Color', 'w');

%% 光线追踪
for i = 1:num_rays
angle = theta(i);
x0 = 0; y0 = 0; z0 = -5e-3;
vx1 = sin(angle); vy1 = 0; vz1 = cos(angle);
t1 = (lens_z - z0) / vz1;
x1 = x0 + vx1 * t1;
y1 = y0 + vy1 * t1;
z1 = lens_z;

n1 = 1.0; n2 = 1.5;
theta2 = asin(n1/n2 * sin(angle));
vx2 = sin(theta2); vy2 = 0; vz2 = cos(theta2);
t2 = (screen_z - lens_z) / vz2;
x2 = x1 + vx2 * t2;
y2 = y1 + vy2 * t2;
z2 = screen_z;

scale1 = min(1, t / num_frames);
scale2 = max(0, t/num_frames - 0.5) * 2;

xa = x0 + vx1 * t1 * scale1;
ya = y0 + vy1 * t1 * scale1;
za = z0 + vz1 * t1 * scale1;
plot3([x0 xa], [y0 ya], [z0 za], 'Color', [1 1 1], 'LineWidth', 1.2);

if t > num_frames/2
xb = x1 + vx2 * t2 * scale2;
yb = y1 + vy2 * t2 * scale2;
zb = z1 + vz2 * t2 * scale2;
plot3([x1 xb], [y1 yb], [z1 zb], 'Color', [1 1 1]*0.8, ...
'LineStyle','--', 'LineWidth', 1);
end
end

%% 彩色动态干涉牛顿环(模拟RGB三波段)
[xg, yg] = meshgrid(linspace(-0.002, 0.002, 400));
rg = sqrt(xg.^2 + yg.^2);
zg = screen_z + 0.0002 * sin(2*pi*t/num_frames) * sin(50 * rg); % 三维起伏
lambda_rgb = [620e-9, 550e-9, 470e-9]; % R G B
img = zeros([size(xg), 3]);

for k = 1:3
phase = pi * rg.^2 / (lambda_rgb(k) * R) + 2*pi*t/num_frames;
img(:,:,k) = 0.5 + 0.5 * cos(phase).^2;
end

surf(xg, yg, zg, img, 'EdgeColor', 'none');

%% 可视化透镜
[X,Y,Z] = cylinder(linspace(0.001, 0.01, 50), 60);
Z = -Z * 1e-3 + 0.5e-3;
surf(X, Y, Z + lens_z, 'FaceAlpha', 0.3, 'EdgeColor', 'none', ...
'FaceColor', [0.3 0.6 1]);

%% 写入帧
raw_frame = getframe(fig);
resized_frame = imresize(raw_frame.cdata, [600 800]);
writeVideo(v, im2frame(resized_frame));
end

close(v);

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

前言

太可恶了,我刚学完C++那些基础理论,像泛型编程,类,然后再没什么刷题经验的情况下,来了Leetcode,我就说这咋实现,感觉头都大了,怎么写怎么不对,然后一看发现,数据外部传入,我只需要补充类函数实现就行了,像int main()这些根本不用写,我只需要写个处理方法就行,气死我了!!!

学算法,刷力扣(leetcode)不知道怎么刷?来看看,我把刷题网站上线了!最强刷题攻略!_哔哩哔哩_bilibili

代码随想录

二分

第704题

704. 二分查找 - 力扣(LeetCode)

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
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0;
int right=nums.size()-1;
int mid;
while(left<=right)
{
mid=left+(right-left)/2;
if(nums[mid]==target)
{
return mid;
}
if(nums[mid]>target)
{
right=mid-1;/*为什么加一,因为边界条件一定不满足,可以丢弃,而且可以实现最终结束循环,left>right-1!!!*/
}
if(nums[mid]<target)
{
left=mid+1;/*为什么加一,因为边界条件一定不满足,可以丢弃,而且可以实现最终结束循环,left+1>right!!!*/
}
}
return -1;
}
};
/*这道题目的前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当大家看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。
第一种写法,我们定义 target 是在一个在左闭右闭的区间里,也就是[left, right] (这个很重要非常重要)。
while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
如果说定义 target 是在一个在左闭右开的区间里,也就是[left, right) ,那么二分法的边界处理方式则截然不同。
while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]*/

第35题

35. 搜索插入位置 - 力扣(LeetCode)

第34题

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

第69题

69. x 的平方根 - 力扣(LeetCode)

第367题

367. 有效的完全平方数 - 力扣(LeetCode)

哈希

第242题

242. 有效的字母异位词 - 力扣(LeetCode)

image-20250409211853398

好家伙,这就速度能比,那个内存分布有点奇怪,提交次数不一样,内存分布大小就不一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
bool isAnagram(string s, string t) {
int hash[26]={0};/*切记不要忘了化0!!!C++ 中的局部变量如果没有手动初始化,值是随机的垃圾值。你需要把 hash 初始化为全 0*/
for(auto i:s)
{
hash[i-'a']++;
}
for(auto j:t)
{
hash[j-'a']--;
}
for(int n=0;n<26;n++)
{
if(hash[n]!=0)
{
return 0;
}

}
return 1;
}
};

第349题

349. 两个数组的交集 - 力扣(LeetCode)

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
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> u1(nums1.begin(),nums1.end());//记住vector!!!很有说法
//他们之间相互转化很有意思,iterator
set<int> u2;//目的是帮我去重!!!
for(auto i:nums2)
{
if(u1.find(i)!=u1.end())//记住这些方法!,因为find没有则返回.end()
{
u2.insert(i);//vector与set,insert不一样
}
}
vector<int>num;//我的返回值是vector
for(auto i:u2)
{
num.push_back(i);
}
return num;
}
};
/*因为题目改了,所以我也可以用数组,因为范围小了,习惯性数组都要大一点hash[1005],因为要给hash碰撞腾出空间*/
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> s1;
vector<int> vec;
vec.reserve(1000);
int hash[1005]={0};
for(int i:nums1)
{
hash[i]=1;
}
for(int j:nums2)
{
if(hash[j]==1)
{
s1.insert(j);
}
}
for(int a:s1)
{
vec.push_back(a);
}
return vec;
}

};//但是数组的空间占用更多了

第202题

202. 快乐数 - 力扣(LeetCode)

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
class Solution {
public:
int Sum(int n)
{
int m=0;
while(n)
{
m+=(n%10)*(n%10);
n=n/10;
//这里写的好,要实现一个数每一项都进行一个操作,就用while循环判定,从最后一位向高位推进,每次丢掉最后一位就行了!!!!
}
return m;
}
//这个地方就是来验证是否出现过,判定是否是死循环,提前退出,避免时间浪费
unordered_set<int> s1;
bool isHappy(int n) {
while(true)
{
if(n==1)
{
return true;
}

s1.insert(n);
n=Sum(n);
if(s1.find(n)!=s1.end())
{
return false;
}
}
}
};//判定一个元素是否在一个整体里出现过就用hash

第1题

1. 两数之和 - 力扣(LeetCode)

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
class Solution {
public://当时学了STL,但不了解咋做题,直接给我弄红温了
vector<int> twoSum(vector<int>& nums, int target) {
for(int i = 0; i < nums.size(); i++){
for(int j = i + 1; j < nums.size(); j++){
if(nums[i] + nums[j] == target){
return {i,j};
}
}
}
return {0,0};
}
};/*这一次写出来,是因为要蓝桥杯了,所以临时抱佛脚,赶紧来做题,所有耐下心慢慢看我的问题,然后给我说int main有问题,我就知道了,所以稍加修改*/
//当然,看这个题还有个原因是刚好看了hash,来试试,显然没有头绪,所以我决定看看代码随想录了。
/*因为本题,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。*/
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int>mp;//map就是遇到有下标保存输出的情况
for(int i=0;i<nums.size();i++)
{
auto iter=mp.find(target-nums[i]);/*明确自己的目标哦,因为find返回的地址,所以用迭代器去接收*/
if(iter!=mp.end())
{
return {iter->second,i};
}
mp.insert(pair<int,int>(nums[i],i));
}
return {};/*根据题目,虽然我们知道一定会有结果,但一定还是写上如果找不到的情况,增加代码的健壮性,return接相当于break,只不过return更强,代表直接结束,break只能循环里用!!!*/
}
};//切记我们要查找什么,要得到什么,查的放key(因为可以用find(key)返回),要得到的什么,得到的用value,可以iter->second()来查找!
  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。

  • set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。

  • std::map 和std::multimap 的key也是有序的有序才用红黑树为底层的,无序直接用哈希表为底层的

  • map用来做什么

  • map中key和value分别表示什么

map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)

接下来是map中key和value分别表示什么。

这道题 我们需要 给出一个元素,判断这个元素是否出现过,如果出现过,返回这个元素的下标。

那么判断元素是否出现,这个元素就要作为key,所以数组中的元素作为key,有key对应的就是value,value用来存下标。

所以 map中的存储结构为 {key:数据元素,value:数组元素对应的下标}。

在遍历数组的时候,只需要向map去查询是否有和目前遍历元素匹配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。

过程一

动态规划

第509题

509. 斐波那契数 - 力扣(LeetCode)

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
class Solution {
public:
int fib(int n) {
if(n==0||n==1)
{
return n;
}
return fib(n-1)+fib(n-2);

}
};//暴力,从后向前推
//这样是根据函数来感觉,还可以自定义一个数组,向里面存放数据,这样更有感觉,从前向后推
//还可以采用动态规划,剪枝,避免重复运算,使时间复杂度变大
//用的dp[]数组保留来实现
#include<iostream>
using namespace std;
int dp(int n);//这是动态规划
int iteration(int n);//这是迭代
int main()
{
int n;
while(1)
{
cout << "输入你想知道的斐波拉契第几项:";
cin >> n;
cout << dp(n) <<" --动态规划"<< endl;
cout << iteration(n) <<" --迭代"<< endl;
}
}
int dp(int n)
{
int dp[1000] = { 0,1 };
for (int i = 0; i < n; i++)
{
dp[i + 2] = dp[i] + dp[i + 1];
}
return dp[n];
}
int iteration(int n)
{
if (n == 1 || n == 2)
{
return 1;
}
int a = 1, b = 1;
for (int i = 0; i < n - 2; i++)
{
int temp = a + b;
a = b;
b = temp;
}
return b;
}

第70题

70. 爬楼梯 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
int climbStairs(int n) {
if(n==1||n==2)
{
return n;
}
return climbStairs(n-1)+climbStairs(n-2);
//考虑所有可能实现的,然后加上去,这就是马尔科夫链那种呀
//切记这里是俩,所以我们至少得有俩终止条件,否则会无限递归停不下来!!!!
}
};
//暴力,但是已经超出时间了,因为同Fibonacci一样,越是后面越是指数级增长,所以我们需要动态规划减枝

vector

动态数组,单端数组(在堆中开的)

头文件:

1
#include<vector>

==算法要学会画图,数形结合!!!!==

img

C++ STL 常用函数_c++ stl 常用函数-CSDN博客

C++ STL详解超全总结(快速入门STL)-CSDN博客

蓝桥杯算法竞赛系列第0章——蓝桥必考点及标准模板库STL(上)(万字博文,建议抱走)_安然无虞stl-CSDN博客

【两万字精编】蓝桥杯算法竞赛系列第0章——蓝桥必考点及标准模板库STL(下)_stl sprintf-CSDN博客

数组理论基础

数组是存放在连续内存空间上的相同类型数据的集合。数组下标都是从0开始的。

数组可以舍弃下标为0的位置,即直接设计arr[0]=0占位,这样子可以很好和现实世界映射!

字符串处理

二分法(最快了)/我记得老师提过牛顿迭代法,那是个什么

【二分查找】详细图解_二分法算法流程图-CSDN博客

二分法详解:概念、应用与实战-CSDN博客

是一种在==有序==数组中查找某一特定元素的搜索算法,这种搜索算法**每一次比较都使搜索范围缩小一半,时间复杂度是log(n)**(高中数学补充过嘞)

  • 一是有序数组(这里可能是**==整体有序==**比如[1,2,3,4,5],也有可能是==局部有序==比如[4,5,1,2,3]),
  • 二是特定元素(也有可能是满足特定的条件)。由定义我们大概就知道了二分法的应用场景,在有序数组中找特定值都可以考虑用二分法
  • 三不能有重复

但是千万不要一直纠结中间的数字两边的数字数量不一样这个问题,因为:

  • 两边数量不一样是一定会出现的情况

  • 但是这种情况并不影响我们对中间数字和目标数字大小关系的判断

    • 只要中间数字大于目标数字,就排除右边的

    • 只要中间数字小于目标数字,就排除左边的

      ==一个个体在整体面前微不足道==(无非是多排除一个数字或者少排除一个数字)

      ==真正影响的是中间那个数字到底该不该加入下一次的查找中,也就是边界问题==

二分法的步骤:

我们要确定一个区间[L,R]我们要找到一个性质(由题目条件决定),并且该性质满足一下两点: ①满足二段性 ②答案是二段性的分界点

我们要在一组升序的数组找一个数的下标,那我们肯定是先拿中间的与他进行比较,比较大小的判断,其实就相当于是这个性质,且这个性质满足二段性,将大于和小于我们要查找的值分为两段,而我们的查找结果就是分界点

思路分析

二分法题目都可以分下面三步:

  1. 确定是否满足二分法的使用条件有序数组与查找特定元素,题目中a有序,查找的是指定元素test,满足条件
  2. 确定特定元素test,如:a[pos]=test
  3. 确定边界的变化,根据定义的第二句话,写出代码如下

妙呀,思想:

第一种写法(左闭右闭)
二分法最重要的两个点:

while循环中 left 和 right 的关系,到底是 left <= right 还是 left < right
迭代过程中 middle 和 right 的关系,到底是 right = middle - 1 还是 right = middle
3.1 正向写法(正确演示)
第一种写法:每次查找的区间在[left, right](左闭右闭区间),根据查找区间的定义(左闭右闭区间),就决定了后续的代码应该怎么写才能对。因为定义 target 在[left, right]区间,所以有如下两点:

循环条件要使用while(left <= right),因为当(left == right)这种情况发生的时候,得到的结果是有意义的
if(nums[middle] > target) , right 要赋值为 middle - 1, 因为当前的 nums[middle] 一定不是 target ,需要把这个 middle 位置上面的数字丢弃,那么接下来需要查找范围就是[left, middle - 1]
第二种写法(左闭右开)
4.1 正向写法(正确演示)
第二种写法:每次查找的区间在 [left, right),(左闭右开区间), 根据区间的定义,条件控制应该如下:

循环条件使用while (left < right)
if (nums[middle] > target), right = middle,因为当前的 nums[middle] 是大于 target 的,不符合条件,不能取到 middle,并且区间的定义是 [left, right),刚好区间上的定义就取不到 right, 所以 right 赋值为 middle。(边界条件无效了)

img

补充:二分其实还有这种思想(左开右开),就是一来我们将左右范围各移动一位,使实际范围更大,通过移动不断修正范围,直到最后汇聚到中间,l+1=r,二分查找为什么总是写错?_哔哩哔哩_bilibili但是,这也还有问题(这个动态效果,逐渐迫敛)

image-20250411131126244

贪心

通过每次找局部最优从而推导出全局最优,但是其实很多时候不适用,因为全局最优不一定一直是局部最优。

差分

倍增

快速幂算法

快速幂都能做什么?小小的算法也有大大的梦想_哔哩哔哩_bilibili

快速幂算法(全网最详细地带你从零开始一步一步优化)-CSDN博客

就是二进制的一个实现(位于和右移动)O(logn)

这对吗?

  1. (a + b) % p = (a % p + b % p) % p (1)
  2. (a - b) % p = (a % p - b % p ) % p (2)
  3. (a * b) % p = (a % p * b % p) % p (3)
  4. (abc)%d=(a%db%dc%d)%d;

image-20250410204031745

可以试着自己实现一下快速幂取模(搜到一个这个模重复平方算法)

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
63
64
65
66
67
68
69
70
71
72
73
74
#include<iostream>
using namespace std;
long long p(int d, int m)
{
long long r = 1;
while (m) {

if (m & 1)
{ // 判断 m 的当前位是否为 1
r *= d; // 如果是 1,就将 d 乘入结果 r
}
m = m >> 1;
d = d * d; // 将基数 d 平方 // 右移 m,处理下一个二进制位
}
return r;
}
int main()

{
cout<<p(3, 190);
cin.get();
}//快速幂



#include<iostream>
using namespace std;
long long p(int d, int m,int t)
{
long long r = 1;
while (m) {

if (m & 1)
{ // 判断 m 的当前位是否为 1
r *= d%t; // 如果是 1,就将 d 乘入结果 r
}
m = m >> 1;
d = (d%t) * (d%t); // 将基数 d 平方 // 右移 m,处理下一个二进制位
}

return r%t;
}
int main()

{
cout<<p(3, 190,7);
cin.get();
}//快速幂取模


//模重复平方算法
#include <iostream>
using namespace std;

long long mod_exp(int base, int exp, int mod) {
long long result = 1;
base = base % mod; // 先对底数取模
while (exp > 0) {
if (exp % 2 == 1) { // 如果指数是奇数
result = (result * base) % mod;
}
base = (base * base) % mod; // 每次将底数平方
exp = exp / 2; // 指数右移
}
return result;
}

int main() {
int base = 3;
int exp = 190;
int mod = 7;
cout << "3^190 % 7 = " << mod_exp(base, exp, mod) << endl;
return 0;
}//和我那个是等价的

斐波拉契数列用快速幂找第n项!

image-20250410212752636

image-20250410213055100

image-20250410213210367

龟速乘的根据&实现——慢工出细活

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
long long quick_mul(long long x,long long y,long long mod) 
{
long long ans=0;
while(y!=0){
if(y&1==1)ans+=x,ans%=mod;
x=x+x,x%=mod;
y>>=1;
}
return ans;
}

long long quick_pow(long long x,long long y,long long mod)
{
long long sum=1;
while(y!=0){
if(y&1==1)sum=quick_mul(sum,x,mod),sum%=mod;
x=quick_mul(x,x,mod),x%=mod;
y=y>>1;
}
return sum;
}

实际上,龟速乘的确慢,甚至比直接用开始提到的循环乘法还要慢(因为龟速乘相当于一个自行取模的乘号),然而慢工出细活,正是它的慢最终为我们解决了数据过大时产生的问题。

快速乘

【谈谈知识点】快速幂&龟速乘&快速乘-CSDN博客

快速幂有关的题:Problem - 2035

回溯算法

BFS算法

哈希/散列(一类算法)

我是看的代码随想录

哈希究竟代表什么?哈希表和哈希函数的核心原理_哔哩哔哩_bilibili

通俗易懂->哈希表详解-CSDN博客

算法数据结构基础——哈希表(Hash Table)-CSDN博客

数组是通过索引来取出对应的数,哈希是通过==键值对匹配==来取出对应的数!(python字典,c++里面的unordered map,数组,set)

数组通过整数索引找到对应的值(对应其地址),而hash可以通过字符串等多种多样的键去找到值(随机位置,不代表其地址)

  1. 将任意长度的输入,转换为固定长度的输出

屏幕截图 2025-04-09 124526

不可逆,所以可以用来单向加密(但是毕竟是有限固定长度,所以会有一个很大的问题:哈希冲突——开放寻址法,封闭寻址法)

  1. 数据对比

比较哈希函数计算出的哈希值是否一致,来判定文件是否相同

散列表(哈希表) - 散列函数, 冲突处理, 平均查找长度(ASL)_哔哩哔哩_bilibili

哈希一般用于判定一个东西是否在某个集体里出现过

hash一般有三种:数组(范围可控,数据较小),set(数值大),map(有涉及键值对涉及的时候用)

要枚举的话时间复杂度是O(n),但如果使用哈希表的话, 只需要O(1)就可以做到。(底层先不管,记住键值对匹配就行)

哈希函数:一种处理方式将内容映射到hash表里

哈希表2

因为有限的hash表肯定会出现有数据多余,出现同一个key(hash碰撞)

哈希表3

一般采取拉链法和线性探测法。

拉链法

哈希表4

其实拉链法就是要选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间。

#线性探测法(补空位)

一定要保证tableSize大于dataSize

在C++中,set 和 map 分别提供以下三种数据结构,其底层实现以及优劣如下表所示:

集合 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率
std::set 红黑树 有序 O(log n) O(log n)
std::multiset 红黑树 有序 O(logn) O(logn)
std::unordered_set 哈希表 无序 O(1) O(1)

哈希表大战表红黑树,数据结构性能挑战赛可以看一下别人做的数据视频,hash速度比红黑树(一种平衡二叉搜索树)快很多

映射 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率
std::map 红黑树 key有序 key不可重复 key不可修改 O(logn) O(logn)
std::multimap 红黑树 key有序 key可重复 key不可修改 O(log n) O(log n)
std::unordered_map 哈希表 key无序 key不可重复 key不可修改 O(1) O(1)

当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。

那么再来看一下map ,在map 是一个key value 的数据结构,map中,对key是有限制,对value没有限制的,因为key的存储方式使用红黑树实现的。

虽然std::set和std::multiset 的底层实现基于红黑树而非哈希表,它们通过红黑树来索引和存储数据。不过给我们的使用方式,还是哈希法的使用方式,即依靠键(key)来访问值(value)。所以使用这些数据结构来解决映射问题的方法,我们依然称之为哈希法。std::map也是一样的道理。

总结一下,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法

但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。

set用于去重,且可以用于数据量大,跨越大的地方(避免空间浪费,不需要自己写hash函数去映射!)

直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。

不要小瞧 这个耗时,在数据量大的情况,差距是很明显的。(但是数组不用hash运算,所以速度快,空间换时间)

首先我再强调一下 什么时候使用哈希法,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。

  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。

此时就要选择另一种数据结构:map ,map是一种key value的存储结构,可以用key保存数值,用value再保存数值所在的下标。

C++中map,有三种类型:

映射 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率
std::map 红黑树 key有序 key不可重复 key不可修改 O(log n) O(log n)
std::multimap 红黑树 key有序 key可重复 key不可修改 O(log n) O(log n)
std::unordered_map 哈希表 key无序 key不可重复 key不可修改 O(1) O(1)

std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。

搜索dfs,bfs

动态规划

img

动态规划(记忆化搜索,剪枝)英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。

记忆化搜索,保存!(用哈希表!!!)

状态转移方程:就是个递推公式!(从一个状态到另一个状态就是状态转移)

就是要看这个状态是由什么状态得到的,就是说你的下标和函数分别含义是什么

!!!!

  1. 设计状态 定义一个状态数组dpi

设计状态dp[](是一个大类,每个可能都有一种状态,而我们要在意初始状态方便迭代,(也可以递归嘞)要在意n位置状态,将它的状态细化到n-1/n-2等直系状态,剩下的数学归纳法可证,所以让计算机自己跑)但因为涉及到了递归,就得注意递归要剪枝,不然会超时,因为他们得处于关联状态,这样题才能建立联系,所以dp[]

  1. 写出状态转移方程(只看离得最近的那几个,不要想太多,要找最直接的gua)

然后分析他是什么状态,这种状态可以是随机状态,那么通过转移方程i-1也得是这种状态,即可去可不去(不知道什么状态是因为他是随机状态,那也是一种状态啊,可以分类讨论细化呀)

  1. 设定初始状态

状态转移方程要先写,然后才知道需要几个初始量,

  1. 执行状态转移

然后写了初始量讨论后,再补上状态转移方程

就像数学题,我要先设变量x,然后才能通过x写出相应关系式来满足/表达出方程!!!!

  1. 返回最终解

最后return结果,切记要保证程序的健壮性!

红黑树/AVL树

图论

我在page.pug内插入了
div#react-root // 这是 React 组件的挂载点

block scripts
// 引入 React 打包后的文件
script(src=’/js/bundle.js’)

创建了有关index.js在src里面(src也是为创建的)
还创建了一个webpack.config.js和react.babelrc

装了这些
npm install react react-dom
npm install –save-dev @babel/core @babel/preset-env @babel/preset-react webpack webpack-cli babel-loader
npm install –save-dev @babel/core @babel/cli @babel/preset-env @babel/preset-react babel-loader
然后还要在layout.pug里面加上
//- 弹窗通知
!=partial(‘includes/popup/index’, {}, {cache: true})

block scripts(加上这句话,与上面弹窗通知对齐!)就可以实现react了
我将bundle.js从"C:\Users\86198\myblog\world-map-widget\node_modules\ajv\scripts\bundle.js"移动到了source/js
我在source/js里加了一个world-map.js
在about里的index.md里面加了
<world-map data-dots='[{"start":{"lat":34.0522,"lng":-118.2437},"end":{"lat":40.7128,"lng":-74.0060}},{"start":{"lat":51.5074,"lng":-0.1278},"end":{"lat":48.8566,"lng":2.3522}}]'></world-map>

cao,就是加载不出来地图
我删除了一个index.js
内容/在 index.js 中编写你的 React 组件代码。例如:/
import React from ‘react’;
import ReactDOM from ‘react-dom’;

function App() {
return

Hello from React!
;
}

ReactDOM.render(, document.getElementById(‘react-root’));

我从source/js里把echarts.min.js移动到桌面了
我删除了page.pug里的
block scripts
// 引入 React 打包后的文件
script(src=’/public/js/bundle.js’)