概览
LeetCode Hot:合并区间、不同路径、最小路径和、爬楼梯、颜色分类
SQL语句
LeetCode Hot
2.26 合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
//排序
//对每个区间左端点升序排序
class Solution {
public int[][] merge(int[][] intervals) {
if (intervals.length == 0) {
return new int[0][2];
}
Arrays.sort(intervals, new Comparator<int[]>() { //重载compare,使排序规则为以数组第一列升序排序
public int compare(int[] interval1, int[] interval2) {
return interval1[0] - interval2[0];
}
});
List<int[]> merged = new ArrayList<int[]>();
for (int i = 0; i < intervals.length; ++i) {
int L = intervals[i][0], R = intervals[i][1];
//如果当前区间的左端点在数组 merged 中最后一个区间的右端点之后,那么它们不会重合,我们可以直接将这个区间加入数组 merged 的末尾;
if (merged.size() == 0 || merged.get(merged.size() - 1)[1] < L) {
merged.add(new int[]{L, R});
//否则,它们重合,我们需要用当前区间的右端点更新数组 merged 中最后一个区间的右端点,将其置为二者的较大值。
} else {
merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], R);
}
}
return merged.toArray(new int[merged.size()][]);
}
}
2.27 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
示例 1:
输入:m = 3, n = 7
输出:28
//DP
//每个位置的路径 = 该位置左边的路径 + 该位置上边的路径
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
for (int i = 0; i < n; i++) dp[0][i] = 1; //边界只能往右或者下,只有一种可能
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int i = 1; i < m; i++) { //状态方程:dp[i][j] = dp[i-1][j] + dp[i][j-1]
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
}
//优化版本,空间复杂度O(n)
class Solution {
public int uniquePaths(int m, int n) {
int[] cur = new int[n]; //只需使用列数的一维数组
Arrays.fill(cur,1);
for (int i = 1; i < m;i++){
for (int j = 1; j < n; j++){
//cur[j] = cur[j] + cur[j-1]:
/*
*cur[j]:以前未更新的路径数,即上一次i循环(上一行)当前列的路径
*cur[j-1]:更新后,即本行左边一个的路径
*即左边路径+上边路径,妙啊!
*/
cur[j] += cur[j-1] ;
}
}
return cur[n-1];
}
}
2.28 最小路径和
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例 1:
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
class Solution {
public int minPathSum(int[][] grid) {
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(i == 0 && j == 0) continue;
else if(i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j];
else if(j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j];
else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j];
}
}
return grid[grid.length - 1][grid[0].length - 1];
}
}
2.29 爬楼梯
同剑指offer8题,青蛙跳台阶,dp算法
2.30
/*
dp[i][j] 代表 word1 到 i 位置转换成 word2 到 j 位置需要最少步数
所以,
当 word1[i] == word2[j],dp[i][j] = dp[i-1][j-1];
当 word1[i] != word2[j],dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1
其中,dp[i-1][j-1] 表示替换操作,dp[i-1][j] 表示删除操作,dp[i][j-1] 表示插入操作
注意,针对第一行,第一列要单独考虑.
*/
//DP
class Solution {
public int minDistance(String word1, String word2) {
int n1 = word1.length();
int n2 = word2.length();
int[][] dp = new int[n1 + 1][n2 + 1];
// 第一行
for (int j = 1; j <= n2; j++) dp[0][j] = dp[0][j - 1] + 1;
// 第一列
for (int i = 1; i <= n1; i++) dp[i][0] = dp[i - 1][0] + 1;
for (int i = 1; i <= n1; i++) {
for (int j = 1; j <= n2; j++) {
if (word1.charAt(i - 1) == word2.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1];
else dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1;
}
}
return dp[n1][n2];
}
}
2.30 颜色分类
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库的sort函数的情况下解决这个问题。
示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
//双指针
//0 挪到最前面,2 挪到最后面
//注意 2 挪完如果换出来的不是 1,那么指针要回退,因为 0 和 2 都是需要再次移动的
class Solution {
public void sortColors(int[] nums) {
int n = nums.length;
if (n < 2) {
return;
}
//双指针
int p = 0, q = n - 1;
for (int i = 0; i <= q; ++i) {
if (nums[i] == 0) {
nums[i] = nums[p];
nums[p] = 0;
++p;
}
if (nums[i] == 2) {
nums[i] = nums[q];
nums[q] = 2;
--q;
if (nums[i] != 1) {
--i;
}
}
}
return;
}
}
SQL语句
SQL语句
创建表
CREATE TABLE Student
(
Id INT NOT NULL UNIQUE PRIMARY KEY,
Name VARCHAR(20) NOT NULL,
Age INT NULL,
Gender VARCHAR(4) NULL
);
删除表
DROP TABLE <表名>;
清空表
TRUNCATE TABLE <表名>;
修改表
-- 添加学生表`Phone`列
ALTER TABLE Student ADD Phone VARCHAR(15) NULL;
-- 删除学生表`Phone`列
ALTER TABLE Student DROP COLUMN Phone;
-- 修改学生表`Phone`列
ALTER TABLE Student MODIFY Phone VARCHAR(13) NULL;
查询
SELECT [ALL | DISTINCT] <目标列表达式>[,<目标列表达式>]…
FROM <表名或视图名>[,<表名或视图名>]…
[WHERE <条件表达式>]
[GROUP BY <列名> [HAVING <条件表达式>]]
[ORDER BY <列名> [ASC|DESC]…]
SQL查询语句的顺序:SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY。
SELECT、FROM是必须的,HAVING子句只能与 GROUP BY搭配使用。
SELECT * FROM Student
WHERE Id>10
GROUP BY Age HAVING AVG(Age) > 20
ORDER BY Id DESC
插入
-- 插入不存在的数据
INSERT INTO Student (Name,Age,Gender) VALUES ('Andy',30,'女');
-- 将查询的数据插入到数据表中
INSERT INTO Student (Name,Age,Gender)
SELECT Name,Age,Gender FROM Student_T WHERE Id >10;
更新
-- 将Id在(10,100)的Age加1
UPDATE Student
SET Age= Age+1
WHERE Id>10 AND Id<100;
删除
-- 删除Id小于10的数据记录
DELETE FROM Student WHERE Id<10;
索引
索引是一种特殊的查询表,可以被数据库搜索引擎用来加速数据的检索。简单说来,索引就是指向表中数据的指针。数据库的索引同书籍后面的索引非常相像。
例如,如果想要查阅一本书中与某个特定主题相关的所有页面,你会先去查询索引(索引按照字母表顺序列出了所有主题),然后从索引中找到一页或者多页与该主题相关的页面。
索引能够提高 SELECT 查询和 WHERE 子句的速度,但是却降低了包含 UPDATE语句或 INSERT 语句的数据输入过程的速度。索引的创建与删除不会对表中的数据产生影响。
-- 建立学生表索引:单一字段Id索引倒序
CREATE UNIQUE INDEX INDEX_SId ON Student (Id DESC);
-- 建立学生表索引:多个字段Id、Name索引倒序
CREATE UNIQUE INDEX INDEX_SId_SName ON Student (Id DESC,Name DESC);
UNIQUE:表明此索引的每一个索引值只对应唯一的数据记录 CLUSTER:表明建立的索引是聚集索引 次序:可选ASC(升序)或DESC(降序),默认ASC
-- 删除学生表索引
INDEX_SId DROP INDEX INDEX_SId;
视图
视图无非就是存储在数据库中并具有名字的 SQL 语句,或者说是以预定义的 SQL查询的形式存在的数据表的成分。
视图可以包含表中的所有列,或者仅包含选定的列。视图可以创建自一个或者多个表,这取决于创建该视图的 SQL 语句的写法。
视图,一种虚拟的表,允许用户执行以下操作:
-
以用户或者某些类型的用户感觉自然或者直观的方式来组织数据;
-
限制对数据的访问,从而使得用户仅能够看到或者修改(某些情况下)他们需要的数据;
-
从多个表中汇总数据,以产生报表。
创建视图
CREATE VIEW <视图名>
AS SELECT 查询子句
[WITH CHECK OPTION]
查询子句:子查询可以是任何SELECT语句,但是常不允许含有 ORDER BY 子句和 DISTINCT 短语;
WITH CHECK OPTION:表示对UPDATE、INSERT、DELETE操作时要保证更新。
CREATE VIEW VIEW_Stu_Man
AS SELECT * FROM Student WHERE Gender = '男'
WITH CHECK OPTION;
删除视图
DROP VIEW <视图名>;
ORDER BY
ORDER BY 子句根据一列或者多列的值,按照升序或者降序排列数据。某些数据库默认以升序排列查询结果
SELECT [ALL | DISTINCT] <目标列表达式>[,<目标列表达式>]…
FROM <表名或视图名>[,<表名或视图名>]…
[WHERE <条件表达式>]
[ORDER BY <列名>] [ASC | DESC];
LIKE
LIKE 子句通过通配符来将一个值同其他相似的值作比较。可以同 LIKE 运算符一起使用的通配符有两个:
%:替代 0 个或多个字符
_:替代一个字符
SELECT FROM table_name
WHERE column LIKE 'XXXX%'
HAVING
HAVING 子句使你能够指定过滤条件,从而控制查询结果中哪些组可以出现在最终结果里面。
WHERE 子句对被选择的列施加条件,而 HAVING 子句则对 GROUP BY 子句所产生的组施加条件。
SELECT ID, NAME, AGE, ADDRESS, SALARY
FROM CUSTOMERS
GROUP BY age
HAVING COUNT(age) >= 2;
DISTINCT
DISTINCT 关键字同 SELECT 语句一起使用,可以去除所有重复记录,只返回唯一项。
SELECT DISTINCT SALARY
FROM CUSTOMERS
ORDER BY SALARY
AND和OR
将 N 个条件用 AND 运算符结合在一起。对于 SQL 语句要执行的动作来说——无论是事务还是查询,AND 运算符连接的所有条件都必须为 TRUE。
SELECT ID, NAME, SALARY
FROM CUSTOMERS
WHERE SALARY > 2000 AND age < 25;
对于 SQL 语句要执行的动作来说——无论是事务还是查询,OR 运算符连接的所有条件中只需要有一个为 TRUE 即可。
SELECT ID, NAME, SALARY
FROM CUSTOMERS
WHERE SALARY > 2000 OR age < 25;
UNION
UNION 子句/运算符用于将两个或者更多的 SELECT 语句的运算结果组合起来。在使用 UNION 的时候,每个 SELECT 语句必须有相同数量的选中列、相同数量的列表达式、相同的数据类型,并且它们出现的次序要一致,不过长度不一定要相同。
SELECT Txn_Date FROM Store_Information
UNION
SELECT Txn_Date FROM Internet_Sales;
UNION ALL 子句:
UNION ALL 运算符用于将两个 SELECT 语句的结果组合在一起,重复行也包含在内。
INTERSECT子句:
用于组合两个 SELECT 语句,但是只返回两个 SELECT 语句的结果中都有的行。
EXCEPT 子句:
组合两个 SELECT 语句,并将第一个 SELECT 语句的结果中存在,但是第二个SELECT 语句的结果中不存在的行返回。
JOIN
连接(JOIN) 子句用于将数据库中两个或者两个以上表中的记录组合起来。连接通过共有值将不同表中的字段组合在一起。
SQL 中有多种不同的连接:
内连接(INNER JOIN):当两个表中都存在匹配时,才返回行。
左连接(LEFT JOIN):返回左表中的所有行,如果左表中行在右表中没有匹配行,则结果中右表中的列返回空值。
右连接(RIGHT JOIN):恰与左连接相反,返回右表中的所有行,如果右表中行在左表中没有匹配行,则结果中左表中的列返回空值。
全连接(FULL JOIN):返回左表和右表中的所有行。当某行在另一表中没有匹配行,则另一表中的列返回空值
SELECT ID, NAME, AMOUNT, DATE
FROM CUSTOMERS INNER
JOIN ORDERS
ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID;
总结
1.算法真的很奇妙,只有深入理解它才能体会到它的美妙,27题用DP求不同路径时,使用一维数组存储路径数非常巧妙;
2.今天复习了SQL语句,因为是客户端,所以数据库要求不算高,只复习了基本得知识点。