Fork me on GitHub
0%

题目

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。说明:你不能倾斜容器。

样例

输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。具体可参考leetcode官方题解。

输入:height = [1,1]
输出:1

说明

  • n == height.length
  • 2 <= n <= 10^5
  • 0 <= height[i] <= 10^4
    左右指针分别指向数组的左右两端,移动数字较小的那个指针。移动大的话,如果移动后的值变大,还是取决于小的。如果变小,那就更小了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func maxArea(height []int) int {
left,right:=0,len(height)-1
ans:=0
for left<right{
tmp:=min(height[left],height[right])*(right-left)
if tmp>ans{
ans = tmp
}
if(height[left]>height[right]){
right--
}else{
left++
}
}
return ans
}

func min(a,b int)int{
if a>b{
return b
}
return a
}

题目

给你一个长桌子,桌子上盘子和蜡烛排成一列。给你一个下标从 0 开始的字符串 s ,它只包含字符 ‘‘ 和 ‘|’ ,其中 ‘‘ 表示一个 盘子 ,’|’ 表示一支 蜡烛 。

阅读全文 »

题目

给定一个整数 num,将其转化为 7 进制,并以字符串形式输出。

阅读全文 »

题目

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

阅读全文 »

题目

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

输入

nums = [1,3,5,6], target = 5

输出

2

输入

nums = [1,3,5,6], target = 2

输出

1

思路

  • 给出一个已经从小到大排序后的数组,要求在数组中找到插入 target 元素的位置。
  • 经典的二分搜索的变种题,在有序数组中找到最后一个比 target 小的元素。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func searchInsert(nums []int, target int) int {
var low,high int=0,len(nums)
var mid int = low+((high-low)>>1)
for low<high {//注意是小于
if nums[mid]==target{
return mid
}else if nums[mid]<target{
low = mid+1
}else{
high=mid
}
mid = low+(high-low)>>1
}
return low
}

题目

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

阅读全文 »

  • 题目

    给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

阅读全文 »

String

比较

  • 必须使用equals()方法而不能用==
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Main {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
}
}
//true true

public class Main {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "HELLO".toLowerCase();
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
}
}
// false true
  • 两个字符串用==equals()比较都为true,但实际上那只是Java编译器在编译期,会自动把所有相同的字符串当作一个对象放入常量池,自然s1s2的引用就是相同的。
  • 字符串操作不改变原字符串内容,而是返回新字符串;

常用接口

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
// 是否包含子串:
"Hello".contains("ll"); // true
"Hello".indexOf("l"); // 2
"Hello".lastIndexOf("l"); // 3
"Hello".startsWith("He"); // true
"Hello".endsWith("lo"); // true
"Hello".substring(2); // "llo"

" \tHello\r\n ".trim(); // "Hello"


"".isEmpty(); // true,因为字符串长度为0
" ".isEmpty(); // false,因为字符串长度不为0
" \n".isBlank(); // true,因为只包含空白字符
" Hello ".isBlank(); // false,因为包含非空白字符

s.replace('l', 'w'); // "hewwo",所有字符'l'被替换为'w'

String s = "A,,B;C ,D";
s.replaceAll("[\\,\\;\\s]+", ","); // "A,B,C,D"

String s = "A,B,C,D";
String[] ss = s.split("\\,"); // {"A", "B", "C", "D"}

String[] arr = {"A", "B", "C"};
String s = String.join("***", arr); // "A***B***C"

// 格式化
String s = "Hi %s, your score is %d!";
System.out.println(s.formatted("Alice", 80));
System.out.println(String.format("Hi %s, your score is %.2f!", "Bob", 59.5));

String.valueOf(45.67); // "45.67"

int n1 = Integer.parseInt("123"); // 123
int n2 = Integer.parseInt("ff", 16); // 按十六进制转换,255

//转换编码后,就不再是char类型,而是byte类型表示的数组。
byte[] b1 = "Hello".getBytes(); // 按系统默认编码转换,不推荐
byte[] b2 = "Hello".getBytes("UTF-8"); // 按UTF-8编码转换
byte[] b2 = "Hello".getBytes("GBK"); // 按GBK编码转换
byte[] b3 = "Hello".getBytes(StandardCharsets.UTF_8); // 按UTF-8编码转换

//把已知编码的byte[]转换为String
byte[] b = ...
String s1 = new String(b, "GBK"); // 按GBK转换
String s2 = new String(b, StandardCharsets.UTF_8); // 按UTF-8转换
  • contains()方法的参数是CharSequence CharSequenceString的父类。

  • 使用trim()方法可以移除字符串首尾空白字符。空白字符包括空格,\t\r\n

  • 另一个strip()方法也可以移除字符串首尾空白字符。类似中文的空格字符\u3000也会被移除

  • 任意基本类型或引用类型转换为字符串,使用静态方法valueOf()

1
2
3
4
5
6
7
8
9
10
11
public class Main {
public static void main(String[] args) {
char[] cs = "Hello".toCharArray();
String s = new String(cs);
System.out.println(s);
cs[0] = 'X';
System.out.println(s);
}
}
//Hello
//Hello
  • String的不变性设计可以看出,如果传入的对象有可能改变,我们需要复制而不是直接引用。

  • String则以byte[]存储:如果String仅包含ASCII字符,则每个byte存储一个字符,否则,每两个byte存储一个字符,这样做的目的是为了节省内存。

StringBuilder

  • 为了高效拼接字符串,Java标准库提供了StringBuilder,它是一个可变对象,可以预分配缓冲区,往StringBuilder中新增字符时,不会创建新的临时对象。
1
2
3
4
5
6
7
8
9
10
public class Main {
public static void main(String[] args) {
var sb = new StringBuilder(1024);
sb.append("Mr ")
.append("Bob")
.append("!")
.insert(0, "Hello, ");
System.out.println(sb.toString());
}
}

普通的字符串+操作,并不需要将其改写为StringBuilder,因为Java编译器在编译时就自动把多个连续的+操作编码为StringConcatFactory的操作。在运行期,StringConcatFactory会自动把字符串连接操作优化为数组复制或者StringBuilder操作。

StringJoin

  • StringJoiner 用分隔符拼接数组的需求
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
public class Main {
public static void main(String[] args) {
String[] names = {"Bob", "Alice", "Grace"};
var sj = new StringJoiner(", ");
for (String name : names) {
sj.add(name);
}
System.out.println(sj.toString());
}
}
//Bob, Alice, Grace


public class Main {
public static void main(String[] args) {
String[] names = {"Bob", "Alice", "Grace"};
var sj = new StringJoiner(", ", "Hello ", "!");
for (String name : names) {
sj.add(name);
}
System.out.println(sj.toString());
}
}
//Hello Bob, Alice, Grace!

String[] names = {"Bob", "Alice", "Grace"};
var s = String.join(", ", names);

主键

  • 主键是关系表中记录的唯一标识。主键的选取非常重要:主键不要带有业务含义,而应该使用BIGINT自增或者GUID类型。主键也不应该允许NULL

  • 所以,选取主键的一个基本原则是:不使用任何业务相关的字段作为主键。

    因此,身份证号、手机号、邮箱地址这些看上去可以唯一的字段,均不可用作主键。

  • 作为主键最好是完全业务无关的字段,我们一般把这个字段命名为id。常见的可作为id字段的类型有:

    1. 自增整数类型:数据库会在插入数据时自动为每一条记录分配一个自增整数,这样我们就完全不用担心主键重复,也不用自己预先生成主键;
    2. 全局唯一GUID类型:使用一种全局唯一的字符串作为主键,类似8f55d96b-8acc-4636-8cb8-76bf8abc2f57。GUID算法通过网卡MAC地址、时间戳和随机数保证任意计算机在任意时间生成的字符串都是不同的,大部分编程语言都内置了GUID算法,可以自己预算出主键。
  • 关系数据库实际上还允许通过多个字段唯一标识记录,即两个或更多的字段都设置为主键,这种主键被称为联合主键。

    • 没有必要的情况下,尽量不使用联合主键,因为它给关系表带来了复杂度的上升。

外键

  • 一对多

    • 由于一个班级可以有多个学生,在关系模型中,这两个表的关系可以称为“一对多”,即一个classes的记录可以对应多个students表的记录。
    • students表中,通过class_id的字段,可以把数据与另一张表关联起来,这种列称为外键
    1
    2
    3
    4
    ALTER TABLE students
    ADD CONSTRAINT fk_class_id
    FOREIGN KEY (class_id)
    REFERENCES classes (id);
    1
    2
    ALTER TABLE students
    DROP FOREIGN KEY fk_class_id;
  • 多对多

    • 多对多关系实际上是通过两个一对多关系实现的,即通过一个中间表,关联两个一对多关系,就形成了多对多关系
    • 例如,一个老师可以对应多个班级,一个班级也可以对应多个老师,因此,班级表和老师表存在多对多关系。
    • 通过中间表teacher_class可知teachersclasses的关系
  • 一对一

    • 把一个大表拆成两个一对一的表,目的是把经常读取和不经常读取的字段分开,以获得更高的性能

索引

  • 通过使用索引,可以让数据库系统不必扫描整个表,而是直接定位到符合条件的记录,这样就大大加快了查询速度。

  • 关系数据库会自动对其创建主键索引。使用主键索引的效率是最高的,因为主键会保证绝对唯一。

    1
    2
    ALTER TABLE students
    ADD INDEX idx_score (score);

    唯一索引

  • 设计关系数据表的时候,看上去唯一的列,例如身份证号、邮箱地址等,因为他们具有业务含义,因此不宜作为主键

    1
    2
    3
    # 给该学生表姓名列添加一个唯一索引
    ALTER TABLE students
    ADD UNIQUE INDEX uni_name (name);
    1
    2
    3
    # 只对某一列添加一个唯一约束而不创建唯一索引
    ALTER TABLE students
    ADD CONSTRAINT uni_name UNIQUE (name);

查询

基本查询

1
2
3
4
5
# SELECT * FROM <表名>
# 计算100+200
SELECT 100+200;
# 测试数据库是否连接
SELECT 1;

条件查询

1
2
3
SELECT * FROM <表名> WHERE <条件表达式>
SELECT * FROM students WHERE score >= 80 AND gender = 'M';
SELECT * FROM students WHERE (score < 80 OR score > 90) AND gender = 'M';

投影查询

1
2
3
# SELECT1, 列2, 列3 FROM ...时,还可以给每一列起个别名,这样,结果集的列名就可以与原表的列名不同。它的语法是SELECT1 别名1, 列2 别名2, 列3 别名3 FROM ...
SELECT id, score points, name FROM students;
SELECT id, score points, name FROM students WHERE gender = 'M';

排序

  • 使用ORDER BY可以对结果集进行排序
1
2
3
4
5
6
7
8
9
10
11
# 查询结果集通常是按照id排序的,也就是根据主键排序。加上ORDER BY子句。例如按照成绩从低到高进行排序
SELECT id, name, gender, score FROM students ORDER BY score;
#低到高
SELECT id, name, gender, score FROM students ORDER BY score DESC;
#使用ORDER BY score DESC, gender表示先按score列倒序,如果有相同分数的,再按gender列排序
SELECT id, name, gender, score FROM students ORDER BY score DESC, gender;
#如果有WHERE子句,那么ORDER BY子句要放到WHERE子句后面。例如,查询一班的学生成绩,并按照倒序排序:
SELECT id, name, gender, score
FROM students
WHERE class_id = 1
ORDER BY score DESC;

分页查询

  • 使用SELECT查询时,如果结果集数据量很大,比如几万行数据,放在一个页面显示的话数据量太大,不如分页显示
  • 分页实际上就是从结果集中“截取”出第M~N条记录。这个查询可以通过LIMIT <M> OFFSET <N>子句实现。
  • LIMIT总是设定为pageSize
  • OFFSET计算公式为pageSize * (pageIndex - 1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 每页3条记录。要获取第1页的记录,可以使用LIMIT 3 OFFSET 0
SELECT id, name, gender, score
FROM students
ORDER BY score DESC
LIMIT 3 OFFSET 0;
#查询第2页,那么我们只需要“跳过”头3条记录,也就是对结果集从3号记录开始查询,把OFFSET设定为3
SELECT id, name, gender, score
FROM students
ORDER BY score DESC
LIMIT 3 OFFSET 3;
#查询第4页的时候,OFFSET应该设定为9
SELECT id, name, gender, score
FROM students
ORDER BY score DESC
LIMIT 3 OFFSET 9;
  • OFFSET超过了查询的最大数量并不会报错,而是得到一个空的结果集。

  • 在MySQL中,LIMIT 15 OFFSET 30还可以简写成LIMIT 30, 15

  • OFFSET是可选的,如果只写LIMIT 15,那么相当于LIMIT 15 OFFSET 0

  • 使用LIMIT <M> OFFSET <N>分页时,随着N越来越大,查询效率也会越来越低。

聚合查询

  • 对于统计总数、平均数这类计算,SQL提供了专门的聚合函数,使用聚合函数进行查询,就是聚合查询,它可以快速获得结果。
1
2
3
4
5
6
7
8
9
-- 使用聚合查询:
SELECT COUNT(*) FROM students;
-- 使用聚合查询并设置结果集的列名为num:
SELECT COUNT(*) num FROM students;
SELECT COUNT(*) boys FROM students WHERE gender = 'M';
SELECT AVG(score) average FROM students WHERE gender = 'M';

-- 每页3条记录,通过聚合查询获得总页数
SELECT CEILING(COUNT(*) / 3) FROM students;
函数 说明
SUM 计算某一列的合计值,该列必须为数值类型
AVG 计算某一列的平均值,该列必须为数值类型
MAX 计算某一列的最大值
MIN 计算某一列的最小值
  • 如果聚合查询的WHERE条件没有匹配到任何行,COUNT()会返回0,而SUM()AVG()MAX()MIN()会返回NULL

分组

  • GROUP BY子句指定了按class_id分组,因此,执行该SELECT语句时,会把class_id相同的列先分组,再分别计算。与ODERBY 先查询出结果再筛选不同。
1
2
3
4
5
6
7
8
SELECT class_id, COUNT(*) num FROM students GROUP BY class_id;

-- 因为在任意一个分组中,只有class_id都相同,name是不同的,SQL引擎不能把多个name的值放入一行记录中。因此,聚合查询的列中,只能放入分组的列。
SELECT name, class_id, COUNT(*) num FROM students GROUP BY class_id;

-- 使用多个列进行分组。例如,我们想统计各班的男生和女生人数:
SELECT class_id, gender, COUNT(*) num FROM students GROUP BY class_id, gender;

多表查询

  • 这种多表查询又称笛卡尔查询,使用笛卡尔查询时要非常小心,由于结果集是目标表的行数乘积,对两个各自有100行记录的表进行笛卡尔查询将返回1万条记录,对两个各自有1万行记录的表进行笛卡尔查询将返回1亿条记录。
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
SELECT
students.id sid,
students.name,
students.gender,
students.score,
classes.id cid,
classes.name cname
FROM students, classes;

SELECT
s.id sid,
s.name,
s.gender,
s.score,
c.id cid,
c.name cname
FROM students s, classes c;

SELECT
s.id sid,
s.name,
s.gender,
s.score,
c.id cid,
c.name cname
FROM students s, classes c
WHERE s.gender = 'M' AND c.id = 1;

连接查询

内连接

  1. 先确定主表,仍然使用FROM <表1>的语法;
  2. 再确定需要连接的表,使用INNER JOIN <表2>的语法;
  3. 然后确定连接条件,使用ON <条件...>,这里的条件是s.class_id = c.id,表示students表的class_id列与classes表的id列相同的行需要连接;
  4. 可选:加上WHERE子句、ORDER BY等子句。
1
2
3
4
SELECT s.id, s.name, s.class_id, c.name class_name, s.gender, s.score
FROM students s
INNER JOIN classes c
ON s.class_id = c.id;

外连接

  • INNER JOIN只返回同时存在于两张表的行数据,由于students表的class_id包含1,2,3,classes表的id包含1,2,3,4,所以,INNER JOIN根据条件s.class_id = c.id返回的结果集仅包含1,2,3。

  • RIGHT OUTER JOIN返回右表都存在的行。如果某一行仅在右表存在,那么结果集就会以NULL填充剩下的字段。

  • LEFT OUTER JOIN则返回左表都存在的行。如果我们给students表增加一行,并添加class_id=5,由于classes表并不存在id=5的行,所以,LEFT OUTER JOIN的结果会增加一行,对应的class_nameNULL

  • FULL OUTER JOIN,它会把两张表的所有记录全部选择出来,并且,自动把对方不存在的列填充为NULL

  • ![image-20210616195108976](/Users/hc/Library/Application Support/typora-user-images/image-20210616195108976.png)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 右连接
SELECT s.id, s.name, s.class_id, c.name class_name, s.gender, s.score
FROM students s
RIGHT OUTER JOIN classes c
ON s.class_id = c.id;
# 左连接
SELECT s.id, s.name, s.class_id, c.name class_name, s.gender, s.score
FROM students s
LEFT OUTER JOIN classes c
ON s.class_id = c.id;
# 全外连接
SELECT s.id, s.name, s.class_id, c.name class_name, s.gender, s.score
FROM students s
FULL OUTER JOIN classes c
ON s.class_id = c.id;

修改数据

  • 增删改查,即CRUD:Create、Retrieve、Update、Delete

  • 增、删、改,对应的SQL语句分别是:

    • INSERT:插入新记录;
    • UPDATE:更新已有记录;
    • DELETE:删除已有记录;

插入

  • 基本语法是:INSERT INTO <表名> (字段1, 字段2, …) VALUES (值1, 值2, …);

  • 要注意,字段顺序不必和数据库表的字段顺序一致,但值的顺序必须和字段顺序一致。也就是说,可以写INSERT INTO students (score, gender, name, class_id) ...,但是对应的VALUES就得变成(80, 'M', '大牛', 2)

1
2
3
4
INSERT INTO students (class_id, name, gender, score) VALUES (2, '大牛', 'M', 80);
INSERT INTO students (class_id, name, gender, score) VALUES
(1, '大宝', 'M', 87),
(2, '二宝', 'M', 81);
1
2
3
4
syms t,x,a1,a4,a3,a,b,c,J;
u(t)= a4./(exp(a1*t)+a2+exp(-a3*t))
J = (-1./2)diff(u(t)).^2+(1./2)*a*u(t).^2+1./3*b*u(t).^3+1./4*c*u(t).^4; %
int(J, t, -inf,inf);

更新

  • UPDATE语句的基本语法是:UPDATE <表名> SET 字段1=值1, 字段2=值2, … WHERE …;
  • 在执行UPDATE语句时要非常小心,最好先用SELECT语句来测试WHERE条件是否筛选出了期望的记录集,然后再用UPDATE更新
1
2
3
4
5
UPDATE students SET name='大牛', score=66 WHERE id=1;
UPDATE students SET name='小牛', score=77 WHERE id>=5 AND id<=7;

-- 更新所有记录 要十分小心!!!
UPDATE students SET score=60;

删除

  • 删除数据库表中的记录,我们可以使用DELETE语句。

  • UPDATE类似,不带WHERE条件的DELETE语句会删除整个表的数据

  • DELETE FROM <表名> WHERE ...;
    DELETE FROM students WHERE id=1;
    -- 删除整个表,小心!!!
    DELETE FROM students;
    

前言

抱着想写点什么记录考研的心态,也应某朋友的要求写下这个经验贴。

看完不求点赞转发,如果能从我的经历中获得什么,我会感到开心和欣慰。

阅读全文 »

雨季不再来

感叹与才华横溢,涉猎广泛,亦感叹于悲苦,抑郁童少年,从沉沦到蜕变,又惊觉于古灵精怪,感同深受的细腻情怀。真有血有肉有灵气不同于流俗之人也!

阅读全文 »

题目

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

阅读全文 »