185. 部门工资前三高的所有员工
表: Employee
+--------------+---------+ | Column Name | Type | +--------------+---------+ | id | int | | name | varchar | | salary | int | | departmentId | int | +--------------+---------+ id 是该表的主键列(具有唯一值的列)。 departmentId 是 Department 表中 ID 的外键(reference 列)。 该表的每一行都表示员工的ID、姓名和工资。它还包含了他们部门的ID。
表: Department
+-------------+---------+ | Column Name | Type | +-------------+---------+ | id | int | | name | varchar | +-------------+---------+ id 是该表的主键列(具有唯一值的列)。 该表的每一行表示部门ID和部门名。
公司的主管们感兴趣的是公司每个部门中谁赚的钱最多。一个部门的 高收入者 是指一个员工的工资在该部门的 不同 工资中 排名前三 。
编写解决方案,找出每个部门中 收入高的员工 。
以 任意顺序 返回结果表。
select Department, Employee, Salary
from (
select d.name as 'Department',e.name as 'Employee',e.Salary as 'Salary',dense_rank()over(partition by departmentId order by salary desc )ranks
from Employee e
left join Department d
on e.departmentId=d.id
)t
where ranks<=3
开窗dense_rank() over(partition by sth order by sth)
,先分组然后排序取前三,rank
是跳次排序 1,1,1,4
, dense_rank
是不跳次排序1,1,1,2
, row_number
是顺序1,2,3,4 在之前的文章有提过
197. 上升的温度
表: Weather
+---------------+---------+ | Column Name | Type | +---------------+---------+ | id | int | | recordDate | date | | temperature | int | +---------------+---------+ id 是该表具有唯一值的列。 没有具有相同 recordDate 的不同行。 该表包含特定日期的温度信息
编写解决方案,找出与之前(昨天的)日期相比温度更高的所有日期的 id
。
返回结果 无顺序要求 。
SELECT b.Id
FROM Weather as a,Weather as b
WHERE a.Temperature < b.Temperature
and DATEDIFF(a.RecordDate,b.RecordDate) = -1;
这个比较简单,很基础
196. 删除重复的电子邮箱
表: Person
+-------------+---------+ | Column Name | Type | +-------------+---------+ | id | int | | email | varchar | +-------------+---------+ id 是该表的主键列(具有唯一值的列)。 该表的每一行包含一封电子邮件。电子邮件将不包含大写字母。
编写解决方案 删除 所有重复的电子邮件,只保留一个具有最小 id
的唯一电子邮件。
(对于 SQL 用户,请注意你应该编写一个 DELETE
语句而不是 SELECT
语句。)
(对于 Pandas 用户,请注意你应该直接修改 Person
表。)
运行脚本后,显示的答案是 Person
表。驱动程序将首先编译并运行您的代码片段,然后再显示 Person
表。Person
表的最终顺序 无关紧要
DELETE p1
FROM Person p1
JOIN Person p2 ON p1.email = p2.email
WHERE p1.id > p2.id;
也很简单,连接两张表,条件是他们邮件相同,选择id小的在前面,大的被删除就解决了
13. 罗马数字转整数
罗马数字包含以下七种字符: I
, V
, X
, L
,C
,D
和 M
。
字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000
例如, 罗马数字 2
写做 II
,即为两个并列的 1 。12
写做 XII
,即为 X
+ II
。 27
写做 XXVII
, 即为 XX
+ V
+ II
。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII
,而是 IV
。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX
。这个特殊的规则只适用于以下六种情况:
I
可以放在V
(5) 和X
(10) 的左边,来表示 4 和 9。X
可以放在L
(50) 和C
(100) 的左边,来表示 40 和 90。C
可以放在D
(500) 和M
(1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。
class Solution {
private static final Map<Character,Integer> sv=new HashMap<>();
static{
sv.put('I',1);
sv.put('V', 5);
sv.put('X', 10);
sv.put('L', 50);
sv.put('C', 100);
sv.put('D', 500);
sv.put('M', 1000);
}
public int romanToInt(String s) {
int a = 0;
int n =s.length();
for(int i =0;i<n;i++){
int v = sv.get(s.charAt(i));
if(i<n-1 && v<sv.get(s.charAt(i+1))){
a -= v;
}else{
a +=v;
}
}
return a;
}
}
用哈希表来存储键值对,输入字符串,进遍历 如果小于后面的值用减法,大于用加法
if(i<n-1 && v<sv.get(s.charAt(i+1)))
-
如果条件为真:
-
当前字符的值小于它后面字符的值,说明这是一个减法的情况。例如,在罗马数字中,“IV”表示4,因为“I”(1)在“V”(5)之前,所以需要从结果中减去1。
-
因此,执行
ans -= value
,从结果中减去当前字符的值。
-
-
如果条件为假:
-
当前字符的值大于或等于它后面字符的值,说明这是一个加法的情况。例如,“VI”表示6,因为“I”(1)在“V”(5)之后,或者“V”(5)后面没有更小的数字,所以需要将当前字符的值加到结果中。
-
因此,执行
ans += value
,将当前字符的值加到结果中。
-
17. 电话号码的字母组合
给定一个仅包含数字 2-9
的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = "23" 输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:
输入:digits = "" 输出:[]
示例 3:
输入:digits = "2" 输出:["a","b","c"]
class Solution {
public List<String> letterCombinations(String digits) {
List<String> combinations = new ArrayList<String>();
if (digits.length() == 0) {
return combinations;
} Map<Character, String> phoneMap = new HashMap<Character, String>() {{
put('2', "abc");
put('3', "def");
put('4', "ghi");
put('5', "jkl");
put('6', "mno");
put('7', "pqrs");
put('8', "tuv");
put('9', "wxyz");
}};
backtrack(combinations, phoneMap, digits, 0, new StringBuffer());
return combinations;
}
public void backtrack(List<String> combinations, Map<Character, String> phoneMap, String digits, int index, StringBuffer combination) {
if (index == digits.length()) {
combinations.add(combination.toString());
} else {
char digit = digits.charAt(index);
String letters = phoneMap.get(digit);
int lettersCount = letters.length();
for (int i = 0; i < lettersCount; i++) {
combination.append(letters.charAt(i));
backtrack(combinations, phoneMap, digits, index + 1, combination);
combination.deleteCharAt(index);
}
}
}
}
终止条件的逻辑
当 index == digits.length()
时,意味着:
-
所有数字字符都已经被处理完毕:因为
index
从 0 开始,每处理一个数字字符,index
就加1。当index
等于digits.length()
时,说明已经处理完所有数字字符。 -
当前构建的字母组合是完整的:因为每个数字字符都对应一个字母,且每个字母都被添加到了
combination
中。当所有数字字符都处理完毕时,combination
中的字母数量正好等于digits
的长度,说明已经构建了一个完整的字母组合。
具体例子
假设输入的数字字符串是 "23"
:
-
digits.length()
= 2,表示有两个数字字符需要处理。 -
初始时,
index = 0
,表示从第一个数字字符'2'
开始处理。 -
每次递归调用
backtrack
时,index
加1:-
第一次递归:
index = 0
,处理'2'
。 -
第二次递归:
index = 1
,处理'3'
。 -
第三次递归:
index = 2
,此时index == digits.length()
,说明所有数字字符都已处理完毕。
-
当 index == 2
时,combination
中的字母组合长度为 2(与 digits.length()
相等),说明已经构建了一个完整的字母组合
递归调用
backtrack(combinations, phoneMap, digits, index + 1, combination);
-
递归调用
backtrack
函数,处理下一个数字字符。 -
index + 1
表示移动到下一个数字字符。 -
递归调用时,
combination
已经包含了当前数字对应的字母,因此递归调用会继续构建更长的组合。
5. 回溯操作
combination.deleteCharAt(index);
-
在递归调用返回后,需要进行回溯操作。
-
combination.deleteCharAt(index)
用于移除当前组合中最后一个添加的字母(即当前数字对应的字母)。 -
这一步是为了恢复
combination
的状态,以便尝试下一个字母。
欧克,就到这哈