LeetCode Top100之207, 208,215,287,238,347题

207. 课程表
① 题目描述

中文题目:https://leetcode-cn.com/problems/course-schedule/

② 拓扑排序——查找有向图中是否存在环
  • 课程的学习条件,使用二元数组表示。比如[[1,0]],如果用有向图表示,则应该是:
0
1
  • 其中课程数表示有向图中的节点数,学习条件数用于构造有向图。
  • [[1, 0], [2, 0], [3, 1], [3, 2], [2, 1]]绘图如下:
0
1
2
3
  • 判断有向图中是否存在环: 寻找入度为0的节点,删除该节点以及从该节点出发的边。直至所有节点都被删除,或者不存在入度为0的节点。
  • 上图中,删除节点0,再删除节点1,然后删除节点2,最后删除节点3。没有节点剩余,说明该有向图中不存在环。
  • 程序思想:
    ① 用一个数组统计所有节点的入度,用一个数组记录该节点是否已经被删除。
    ② 循环查找入度为0的节点,更新其他相连节点的入度,并记录该节点已经删除。直至无法找到入度为0的节点。
    ③ 查找每个节点的入度,如果存在入度不为零的节点,则说明存在环;否则,不存在环。
  • 代码如下,运行时间34ms:
public boolean canFinish(int numCourses, int[][] prerequisites) {
    int[] inDegree = new int[numCourses];// 记录每个节点的入度
    boolean[] visited = new boolean[numCourses];// 记录该节点是否已经从有向图中删除
    // 统计每个节点的入度
    for (int i = 0; i < prerequisites.length; i++) {
        inDegree[prerequisites[i][0]]++;
    }

    while (true) {
        int i = 0;
        for (; i < numCourses; i++) {
            if (!visited[i] && inDegree[i] == 0) {
                break;
            }
        }
        if (i == numCourses) {// 没有找到入度为零的节点
            break;
        }
        // 删除入度为零的节点,更新其他节点的入度
        for (int k = 0; k < prerequisites.length; k++) {
            if (prerequisites[k][1] == inDegree[i]) {
                inDegree[prerequisites[k][0]]--;
            }
        }
        visited[i] = true;
    }
    for (int i = 0; i < numCourses; i++) {
        if (inDegree[i] > 0) {
            return false;
        }
    }
    return true;
}
208. 实现 Trie (前缀树)
① 题目描述
  • 中文题目:https://leetcode-cn.com/problems/implement-trie-prefix-tree/
  • 前缀树,又称字典树。结构如下:
  1. 对于每一个节点,从根遍历至某个节点,所有经过的字母形成一个单词。如果这个节点被标记为红色,就表示这个单词存在,否则不存在。
  2. 对于一个单词,只要顺着他从根走到对应的节点,再看这个节点是否被标记为红色就可以知道它是否出现过了。
  3. 插入一个单词时,如果字母对应的节点存在,则继续遍历下一个字母;如果不存在,则创建新节点。并把最后一个字母对应对应的标记为红色,就相当于插入了这个单词。
  4. 这样一来我们查询和插入可以一起完成,所用时间仅仅为单词长度,在这一个样例,便是10。
  5. 前缀树每一层的节点数是 2 6 n 26^n 26n级别,其中n为0 , 1, …。
    在这里插入图片描述
② 构造前缀树
  • 前缀树的结构如下,使用isEnd表示该节点是否一个单词的结尾;使用长度为26的child数组,模拟每个节点后的下一个节点有26种可能。直接使用数组下标与字母对应,如child[0]表示字母a,child[25]表示字母z,无需开辟单独的空间存储字母。
class TreeNode {
    boolean isEnd;// 记录该节点是否为一个单词的结束字母
    TreeNode[] child;// 孩子节点为数组,child[0]表示字母a,初始时每个元素为null

    public TreeNode() {
        child = new TreeNode[26];
        isEnd = false;// 默认不是孩子节点
    }
}
  • 代码如下,运行时间78ms
public class Trie {
    private TreeNode root;
    /**
     * Initialize your data structure here.
     */
    public Trie() {
        root = new TreeNode();
    }
    /**
     * Inserts a word into the trie.
     */
    public void insert(String word) {
        TreeNode cur = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (cur.child[c - 'a'] == null) {// 孩子节点不存在,创建孩子节点
                cur.child[c - 'a'] = new TreeNode();
            }
            cur = cur.child[c - 'a'];// 更新指针
        }
        cur.isEnd = true;// 到达单词末尾
    }
    /**
     * Returns if the word is in the trie.
     */
    public boolean search(String word) {
        TreeNode cur = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (cur.child[c - 'a'] == null) {
                return false;
            }
            cur = cur.child[c - 'a'];
        }
        return cur.isEnd;// 是否为单词结尾
    }
    /**
     * Returns if there is any word in the trie that starts with the given prefix.
     */
    public boolean startsWith(String prefix) {
        TreeNode cur = root;
        for (int i = 0; i < prefix.length(); i++) {
            char c = prefix.charAt(i);
            if (cur.child[c - 'a'] == null) {
                return false;
            }
            cur = cur.child[c - 'a'];
        }
        return true;
    }
}
215. 数组中的第K个最大元素
① 题目描述

中文描述:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/

② 自己的想法:先排序,直接取对应位置的数
  • 代码如下,使用了Arrays.sort实现数组排序,运行时间2ms:
public int findKthLargest(int[] nums, int k) {
    Arrays.sort(nums);
    return nums[nums.length - k];
}
③ 冒泡排序:第k次的结果,就是第k大的数
  • 冒泡排序:① 将序列中相邻元素两两比较,将最大的放在最后面。② 将剩余序列中相邻元素两两比较,将最大的放在最后面重复第② 步,直到只剩下一个数。
  • 代码如下,(用的不是冒泡排序,而是交换排序每次比较都交换元素),运行时间49ms
public int findKthLargest(int[] nums, int k) {
    for (int i = 0; i < k; i++) {
        for (int j = i + 1; j < nums.length; j++) {
            if (nums[i]<nums[j]){
                int temp=nums[i];
                nums[i]=nums[j];
                nums[j]=temp;
            }
        }
    }
    return nums[k-1];
}
287. 寻找重复数
① 题目描述

中文题目:https://leetcode-cn.com/problems/find-the-duplicate-number/

② 使用哈希表
  • 代码如下,运行时间4ms
public int findDuplicate(int[] nums) {
    HashMap<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        if (!map.containsKey(nums[i])) {
            map.put(nums[i], 1);
        } else {
            return nums[i];
        }
    }
    return -1;
}
238. 除自身以外数组的乘积
① 题目描述

中文题目:https://leetcode-cn.com/problems/product-of-array-except-self/

② 暴力法(Time Limit Exceeded
  • 遍历数组,将数组除去自身的其他数相乘。
  • 代码如下,运行超时:
public int[] productExceptSelf(int[] nums) {
    int[] result = new int[nums.length];
    for (int i = 0; i < nums.length; i++) {
        int total = 1;
        for (int j = 0; j < nums.length; j++) {
            if (j != i) {
                total = total * nums[j];
            }
        }
        result[i] = total;
    }
    return result;
}
③ 先算乘积,再做除法
  • 注意: 当当前数不为零时,目标乘积为所有元素的乘积除以它自身;否则,需要重新其计算剩余元素的乘积。
  • 借助了额外的空间存储结果,空间复杂度 O ( n ) O(n) O(n)
  • 代码如下,运行时间1ms
public int[] productExceptSelf(int[] nums) {
    int total = 1;
    int[] result = new int[nums.length];
    for (int i = 0; i < nums.length; i++) {
        total = total * nums[i];
    }
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] != 0) {
            result[i] = total / nums[i];
        } else {
            int temp = 1;
            for (int j = 0; j < nums.length; j++) {
                if (j != i) {
                    temp = temp * nums[j];
                }
            }
            result[i] = temp;
        }
    }
    return result;
}
347. 前K个高频元素
① 题目描述

中文题目:https://leetcode-cn.com/problems/top-k-frequent-elements/

② 自己的想法:迭代查找当前的top1
  • 先使用哈希表统计每个元素出现的个数,然后遍历哈希表k次,每次均查找出当前的top1,将其存入List中并删除哈希表中的该项。
  • 代码如下,运行时间51ms
public List<Integer> topKFrequent(int[] nums, int k) {
    List<Integer> list = new ArrayList<>();
    HashMap<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
    }
    for (int i = 0; i < k; i++) {
        int max = Integer.MIN_VALUE;
        int num = 0;
        for (Integer key : map.keySet()) {// 寻找top1
            if (max < map.get(key)) {
                max = map.get(key);
                num = key; // 记录Top1对应的key
            }
        }
        list.add(num);
        map.remove(num);// 除去当前的top1
    }
    return list;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值