• LeetCode题号[200,299]刷题总结



    201. 数字范围按位与

    给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。

    思路

    • 找出m,n两个端点的共同公共前缀即可
    public int rangeBitwiseAnd(int m, int n) {
        int ans = 0;
        int key = 1<<31;
        while(key != 0){
            if ((m & key) != 0 && (n & key) != 0){
                ans += key;
            } else if ((m & key) != 0 || (n & key) != 0){
                break;
            }
            key >>>= 1;
        }
        return ans;
    }
    
    • 有种相对更简单的方法
    • 每次将n的最右端的1变为0,直到(n <= m)为止,此时与运算结果就是共同公共前缀
    public int rangeBitwiseAnd(int m, int n) {
        while (m < n){
            n &= n-1;
        }
        return m & n;
    }
    

    207. 课程表

    你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。

    在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]

    给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?

    思路

    • 拓扑排序
    class Solution {
        private Map<Integer, List<Integer>> map = new HashMap<>();
        private Queue<Integer> queue = new LinkedList<>();
        private int[] inDegree ;
        public boolean canFinish(int numCourses, int[][] prerequisites) {
            map.clear();
            queue.clear();
            inDegree = new int[numCourses];
            for (int i = 0;i < numCourses;i++){
                map.put(i,new ArrayList<>());
                inDegree[i] = 0;
            }
            for (int i = 0;i < prerequisites.length;i++){
                map.get(prerequisites[i][1]).add(prerequisites[i][0]);
                inDegree[prerequisites[i][0]]++;
            }
            for (int i = 0;i < numCourses;i++){
                if (inDegree[i] == 0){
                    queue.offer(i);
                }
            }
            while (!queue.isEmpty()){
                List<Integer> list = map.get(queue.poll());
                for (Integer i : list){ 
                    inDegree[i]--;
                    if (inDegree[i] == 0){
                        queue.offer(i);
                    }
                }
            }
            for (int i = 0;i < numCourses;i++){
                if (inDegree[i] != 0){
                    return false;
                }
            }
            return true;
        }
    }
    

    209. 长度最小的子数组

    给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

    思路

    • 二分+后缀和
    • 时间复杂度(O(nlogn))
    • 遍历整个数组,当前位置为最右端,二分后缀和
    class Solution {
        public int binarySearch(int s,int left,int right,int sum[]){
            while (left + 1 < right){
                int mid = (left+right) >> 1;
                if (sum[mid] < s){
                    right = mid;
                }
                else{
                    left = mid;
                }
            }
            return sum[left] >= s ? left : -sum.length;
        }
    
        public int minSubArrayLen(int s, int[] nums) {
            if (nums.length == 0){
                return 0;
            }
            int ans = Integer.MAX_VALUE;
            int[] sum = new int[nums.length];
            sum[nums.length - 1] = nums[nums.length - 1];
            for (int i = nums.length - 2;i >= 0;i--){
                sum[i] = sum[i+1] + nums[i];
            }
            for (int i = 0;i < nums.length;i++){
                ans =  Integer.min(ans,i - 
                        binarySearch(s + (i < nums.length - 1 ? sum[i+1] : 0),0,i+1,sum) + 1);
            }
            return ans > sum.length ? 0 : ans ;
        }
    }
    
    • 双指针
    • 涉及连续子数组这种的题目,一般都能用双指针解决,时间复杂度和空间复杂度通常也是最优的
    • 时间复杂度(O(n))
    class Solution {
        public int minSubArrayLen(int s, int[] nums) {
            int left = 0,right = 0,sum = 0,ans = Integer.MAX_VALUE;
            while (left <= right && right < nums.length){
                sum += nums[right++];
                while (sum - nums[left] >= s && left < right){
                    sum -= nums[left++];
                }
                if (sum >= s){
                    ans = Integer.min(ans,right - left);
                }
            }
            return ans == Integer.MAX_VALUE ? 0 : ans;
        }
    }
    

    210. 课程表 II

    现在你总共有 n 门课需要选,记为 0 到 n-1。

    在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]

    给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。

    可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

    思路

    • 跟207题基本一致,等同于将其队列中的数值按照顺序放入数组即可
    class Solution {
        private Map<Integer, List<Integer>> map = new HashMap<>();
        private Queue<Integer> queue = new LinkedList<>();
        private int[] inDegree ;
        public int[] findOrder(int numCourses, int[][] prerequisites) {
            map.clear();
            queue.clear();
            inDegree = new int[numCourses];
            int[] ans = new int[numCourses];
            int cnt = 0;
            for (int i = 0;i < numCourses;i++){
                map.put(i,new ArrayList<>());
                inDegree[i] = 0;
            }
            for (int i = 0;i < prerequisites.length;i++){
                map.get(prerequisites[i][1]).add(prerequisites[i][0]);
                inDegree[prerequisites[i][0]]++;
            }
            for (int i = 0;i < numCourses;i++){
                if (inDegree[i] == 0){
                    queue.offer(i);
                    ans[cnt++] = i;
                }
            }
            while (!queue.isEmpty()){
                List<Integer> list = map.get(queue.poll());
                for (Integer i : list){ 
                    inDegree[i]--;
                    if (inDegree[i] == 0){
                        queue.offer(i);
                        ans[cnt++] = i;
                    }
                }
            }
            return cnt == numCourses ? ans : new int[0];
        }
    
    }
    

    214. 最短回文串(Hard)

    给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。

    思路

    • KMP
    • 由于要求只能在最前面添加字符,所以就先找出原始字符串的前面的最长回文串,再将后面的那段逆转后放到最前面即可
    • 例如,"aacecaaa"的前面最长回文串为"aacecaa",那么我们只需要将最后面的"a"逆转后反到最前面即可
    • 如果用暴力法,那么,时间复杂度为(O(n^{2}))
    • 但是,如果采用KMP,可以使得时间复杂度降为(O(n))
    • KMP就是求最长的相同前后缀,那么如何转换成KMP?
    • 构建一个新的字符串,即s + "#" + s.reverse()
    • 例如,"aacecaaa#aaacecaa"
    • 那么,他的最长公共前后缀就是"aacecaa"
    class Solution {
        public String shortestPalindrome(String s) {
            String str = s + "#" + new StringBuilder(s).reverse();
            int[] next = new int[str.length()];
            int maxLength = 0;
            next[0] = 0;
            for (int i = 1;i < str.length();i++){
                while (maxLength > 0 && str.charAt(i) != str.charAt(maxLength) ){
                    maxLength = next[maxLength - 1];
                }
                if (str.charAt(maxLength) == str.charAt(i)){
                    maxLength++;
                }
                next[i] = maxLength;
            }
            return new StringBuilder(s.substring(next[str.length()-1])).reverse() + s;
        }
    }
    

    215. 数组中的第K个最大元素

    在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

    思路

    • 最小堆
    • PriorityQueue默认为最小堆
    class Solution {
        public int findKthLargest(int[] nums, int k) {
            PriorityQueue<Integer> queue = new PriorityQueue<>();
            int ans = 0;
            for (int num : nums){
                if (queue.size() < k) {
                    queue.add(num);
                } else if (queue.peek() < num){
                    queue.poll();
                    queue.add(num);
                }
            }
            return queue.peek();
        }
    }
    
  • 相关阅读:
    sqlserver获取当前id的前一条数据和后一条数据
    C#实现测量程序运行时间及cpu使用时间
    类库dll引用不成功问题
    合并相同字段
    Android之来历
    XML and JSON 验证
    特殊符号
    git 使用
    格式化字符串:金额
    grunt + sass 使用记录
  • 原文地址:https://www.cnblogs.com/MMMMMMMW/p/13289324.html
Copyright © 2020-2023  润新知