LeetCode 185, 30, 230

目录

185. 部门工资前三高的所有员工

题目链接

185. 部门工资前三高的所有员工

  • Employee的字段为idnamesalarydepartmentId
  • Department的字段为idname

要求

公司的主管们感兴趣的是公司每个部门中谁赚的钱最多。一个部门的 高收入者 是指一个员工的工资在该部门的 不同 工资中 排名前三

编写解决方案,找出每个部门中 收入高的员工

任意顺序 返回结果表。

知识点

  1. count():统计个数的函数。
  2. join on:内连接,使用on做条件限制。
  3. distinct:对某字段去重。

思路

本题总体来说不难,只是对数据的限制比较难想,怎样将员工的工资限制到每个部门的前三名工资里?这里可以换个思路,工资在部门里排前三 不就是 在这个部门中找不到第三个比这个工资大的工资 ,所以可以查询部门中比当前工资大的工资的个数,由于本题限制 排名前三 的工资指的是前三个 不同 的工资,所以在查询时得去重distinct

除此之外就是使用内连接joinEmployeeDepartment这两张表的数据查询到一起,然后使用on限制Employee.departmentId = Department.id

代码

sql 复制代码
select
    d.name Department,
    e.name Employee,
    salary Salary
from
    Employee e
join
    Department d
on
    e.departmentId = d.id
where
    (
        select
            count(distinct eC.salary)
        from
            Employee eC
        where
            eC.salary > e.salary
        and
            e.departmentId = eC.departmentId
    ) < 3

30. 串联所有单词的子串

题目链接

30. 串联所有单词的子串

标签

哈希表 字符串 滑动窗口

思路

本题的思想很像438. 找到字符串中所有字母异位词,438题的思想是统计字符出现的次数,而本题需要统计短字符串出现的次数,共同点就是都不关心内部字符(或短字符串)的顺序,所以可以使用int[](对于短字符串的出现次数,由于字符串不能作为数组索引,所以使用Map<String, Integer>)统计出现次数。

获取短字符串需要将原字符串s划分为指定长度的小段,指定的长度该如何确定?答案是与字符串数组words中每个字符串的长度wordLen保持一致,因为最后这些短字符串的比较对象就是字符串数组words中的字符串。

这种划分的方法共有wordLen种,例如对于s = "barfoothefoobarman", words = ["foo","bar"],划分的结果有以下3种:bar, foo, the, foo, bar, manarf, oot, hef, oob, armrfo, oth, efo, oba, rma。可以看出来不同的划分只是划分的起始字符不同,第一种划分从第一个字符s[0]开始,第二种划分从第二个字符s[1]开始,...,第wordLen种划分从第wordLen个字符s[wordLen]开始,共有wordLen种不同的划分。这里将划分的起始字符的索引称为划分起始索引 。注意一点:原字符串s并不一定能够划分为wordNum个长度为wordLen字符串,如果不够划分,就返回结果。

与438题相同,使用滑动窗口的思想,不过这次滑动窗口中保存的不是一个一个的字符,而是一个一个的短字符串。先初始化滑动窗口,将前wordNum个短字符串加入窗口。初始化滑动窗口后统计words中的字符串出现的次数。

这里可以不使用两个Map分别存储窗口words的短字符串出现次数,然后判断两个Map是否相同。而是复用一个Map,一个字符串在窗口中出现一次,就让这个字符串的出现次数加一;一个字符串在words中出现一次,就让这个字符串的出现次数减一,当一个字符串在Map中出现0次,将这个字符串从Map中移除。在判断窗口内的字符串是否与words的字符串完全一致时直接判断Map是否为空,如果为空,则说明完全一致。

这里不多做描述了,如果很熟悉438题的做法,那么知道上面这些后看代码会好一点。

代码

java 复制代码
class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        List<Integer> res = new ArrayList<>();
        int wordNum = words.length; // 字符串数组的字符串个数
        int wordLen = words[0].length(); // 字符串数组中每个字符串的长度
        int sLen = s.length(); // 原字符串的长度
        for (int i = 0; i < wordLen; i++) { // i是划分起始索引
            if (i + wordNum * wordLen > sLen) { // 如果不够划分,则退出循环
                break;
            }

            // 初始化滑动窗口
            Map<String, Integer> cnt = new HashMap<>(); // 统计各字符串出现的次数
            for (int j = 0; j < wordNum; j++) { // j是已划分子串的个数
                String word = divide(s, i, j, wordLen);
                cnt.put(word, cnt.getOrDefault(word, 0) + 1);
            }

            // 统计words字符串数组的字符串情况,这里复用了cnt
            for (String word : words) {
                cnt.put(word, cnt.getOrDefault(word, 0) - 1);
                if (cnt.get(word) == 0) {
                    cnt.remove(word);
                }
            }

            // 判断cnt是否为空,如果为空,则将窗口的第一个短字符串(的第一个字符)的索引加入结果链表
            if (cnt.isEmpty()) {
                res.add(i);
            }

            // 滑动窗口,start为窗口的第一个字符串(的第一个字符)的索引
            for (int start = i + wordLen; start < sLen - wordNum * wordLen + 1; start += wordLen) {
                String word = divide(s, start, wordNum - 1, wordLen); // 获取新短字符串
                cnt.put(word, cnt.getOrDefault(word, 0) + 1); // 将新短字符串加入窗口
                if (cnt.get(word) == 0) { // 如果一个短字符串在Map中出现0次
                    cnt.remove(word); // 则将它从Map中移除
                }

                word = s.substring(start - wordLen, start); // 获取窗口中的第一个短字符串
                cnt.put(word, cnt.getOrDefault(word, 0) - 1); // 移除窗口中的第一个短字符串
                if (cnt.get(word) == 0) { // 如果一个短字符串在Map中出现0次
                    cnt.remove(word); // 则将它从Map中移除
                }

                // 判断cnt是否为空,如果为空,则将窗口的第一个短字符串(的第一个字符)的索引加入结果链表
                if (cnt.isEmpty()) {
                    res.add(start);
                }
            }
        }
        return res;
    }
    // 返回字符串s在 划分起始索引为i的 划分的 第j个 短字符串
    private String divide(String s, int i, int j, int wordLen) {
        return s.substring(i + j * wordLen, i + (j + 1) * wordLen);
    }
}

230. 二叉搜索树中第K小的元素

题目链接

230. 二叉搜索树中第K小的元素

标签

树 深度优先搜索 二叉搜索树 二叉树

思路

二叉搜索树经常与中序遍历 组合出现,本题也不例外,找二叉搜索树中第K小的元素 就是 找遍历结果的第k个数 ,对中序遍历不了解的可以看这篇文章:94. 二叉树的中序遍历

代码

java 复制代码
class Solution {
    public int kthSmallest(TreeNode root, int k) {
        LinkedList<TreeNode> stack = new LinkedList<>();
        TreeNode curr = root; // 当前节点
        TreeNode pop = null; // 上一个被弹出栈的节点
        while (!stack.isEmpty() || curr != null) {
            if (curr != null) { // 没有处理左子节点的情况
                stack.push(curr);
                curr = curr.left; // 向左子节点移动
            } else {
                TreeNode peek = stack.peek();
                if (peek.right == null || peek.right != pop) { // 没有处理右子节点的情况
                    if (--k == 0) { // 当遍历到第k个节点时会返回peek.val
                        return peek.val;
                    }
                    curr = peek.right; // 向右子节点移动
                    pop = stack.pop();
                } else { // 处理完右子节点的情况
                    pop = stack.pop();
                }
            }
        }
        return -1;
    }
}
相关推荐
m0_5719575838 分钟前
Java | Leetcode Java题解之第543题二叉树的直径
java·leetcode·题解
魔道不误砍柴功3 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2343 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
pianmian13 小时前
python数据结构基础(7)
数据结构·算法
闲晨3 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟4 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
好奇龙猫5 小时前
【学习AI-相关路程-mnist手写数字分类-win-硬件:windows-自我学习AI-实验步骤-全连接神经网络(BPnetwork)-操作流程(3) 】
人工智能·算法
P.H. Infinity5 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天5 小时前
java的threadlocal为何内存泄漏
java
sp_fyf_20245 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘