zoukankan      html  css  js  c++  java
  • Leetcode练习1算法

    一、双指针

    1. 有序数组的 Two Sum

    167. Two Sum II - Input array is sorted (Easy)

    2. 两数平方和

    633. Sum of Square Numbers (Easy)

    反转字符串中的元音字符

    回文字符串

    二、排序

    kth element

    三、贪心思想

    保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。

    1. 分配饼干

    455. Assign Cookies (Easy)

    复制代码
    class Solution {
        public int findContentChildren(int[] g, int[] s) {
            if(g.length == 0 || s.length ==0){
                return 0;
            }
            Arrays.sort(g);
            Arrays.sort(s);
            int num = 0;
            int i=0;
            int j=0;
            while(i<g.length && j < s.length){
                if(g[i] <= s[j]){
                    num++;
                    i++;
                    j++;
                }else{
                    j++;
                }
            }
            return num;
        }
    }
    复制代码

    2. 不重叠的区间个数

    435. Non-overlapping Intervals (Medium)

    复制代码
    class Solution {
        public int eraseOverlapIntervals(int[][] intervals) {
            if(intervals.length == 0){
                return 0;
            }
            Arrays.sort(intervals,Comparator.comparingInt(o -> o[1]));
            int cnt = 1;
            int end = intervals[0][1];
            for(int i=1; i < intervals.length; i++){
                if(intervals[i][0] < end){
                    continue;
                }
                end = intervals[i][1];
                cnt++;
            }
            return intervals.length - cnt;
        }
    }
    复制代码

    3. 投飞镖刺破气球

    452. Minimum Number of Arrows to Burst Balloons (Medium)

    题目描述:气球在一个水平数轴上摆放,可以重叠,飞镖垂直投向坐标轴,使得路径上的气球都被刺破。求解最小的投飞镖次数使所有气球都被刺破。

    也是计算不重叠的区间个数,不过和 Non-overlapping Intervals 的区别在于,[1, 2] 和 [2, 3] 在本题中算是重叠区间。

    复制代码
    class Solution {
        public int findMinArrowShots(int[][] points) {
        if (points.length == 0) {
            return 0;
        }
        Arrays.sort(points, Comparator.comparingInt(o -> o[1]));
        int cnt = 1, end = points[0][1];
        for (int i = 1; i < points.length; i++) {
            if (points[i][0] <= end) {
                continue;
            }
            cnt++;
            end = points[i][1];
        }
        return cnt;
        }
    }
    复制代码

     四、二分查找

    正常实现

    Input : [1,2,3,4,5]
    key : 3
    return the index : 2
    
    复制代码
    public int binarySearch(int[] nums, int key) {
        int l = 0, h = nums.length - 1;
        while (l <= h) {
            int m = l + (h - l) / 2;
            if (nums[m] == key) {
                return m;
            } else if (nums[m] > key) {
                h = m - 1;
            } else {
                l = m + 1;
            }
        }
        return -1;
    }
    复制代码

    时间复杂度

    二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性的算法时间复杂度为 O(logN)。

    m 计算

    有两种计算中值 m 的方式:

    • m = (l + h) / 2
    • m = l + (h - l) / 2

    l + h 可能出现加法溢出,也就是说加法的结果大于整型能够表示的范围。但是 l 和 h 都为正数,因此 h - l 不会出现加法溢出问题。所以,最好使用第二种计算法方法。

    未成功查找的返回值

    循环退出时如果仍然没有查找到 key,那么表示查找失败。可以有两种返回值:

    • -1:以一个错误码表示没有查找到 key
    • l:将 key 插入到 nums 中的正确位置

    变种

    二分查找可以有很多变种,实现变种要注意边界值的判断。例如在一个有重复元素的数组中查找 key 的最左位置的实现如下:

    public int binarySearch(int[] nums, int key) {
        int l = 0, h = nums.length - 1;
        while (l < h) {
            int m = l + (h - l) / 2;
            if (nums[m] >= key) {
                h = m;
            } else {
                l = m + 1;
            }
        }
        return l;
    }

    该实现和正常实现有以下不同:

    • h 的赋值表达式为 h = m
    • 循环条件为 l < h
    • 最后返回 l 而不是 -1

    在 nums[m] >= key 的情况下,可以推导出最左 key 位于 [l, m] 区间中,这是一个闭区间。h 的赋值表达式为 h = m,因为 m 位置也可能是解。

    在 h 的赋值表达式为 h = m 的情况下,如果循环条件为 l <= h,那么会出现循环无法退出的情况,因此循环条件只能是 l < h。以下演示了循环条件为 l <= h 时循环无法退出的情况:

    nums = {0, 1, 2}, key = 1
    l   m   h
    0   1   2  nums[m] >= key
    0   0   1  nums[m] < key
    1   1   1  nums[m] >= key
    1   1   1  nums[m] >= key
    ...
    

    当循环体退出时,不表示没有查找到 key,因此最后返回的结果不应该为 -1。为了验证有没有查找到,需要在调用端判断一下返回位置上的值和 key 是否相等。

    1. 求开方

    69. Sqrt(x) (Easy)

    复制代码
    public int mySqrt(int x) {
        if (x <= 1) {
            return x;
        }
        int l = 1, h = x;
        while (l <= h) {
            int mid = l + (h - l) / 2;
            int sqrt = x / mid;
            if (sqrt == mid) {
                return mid;
            } else if (mid > sqrt) {
                h = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        return h;
    }
    复制代码

    2. 大于给定元素的最小元素

    744. Find Smallest Letter Greater Than Target (Easy)

    复制代码
    class Solution {
        public char nextGreatestLetter(char[] letters, char target) {
            int n = letters.length;
            int l = 0;
            int h = n - 1;
            while(l <= h) {
                int m = l + (h - l)/2;
                if (letters[m] <= target){
                    l = m + 1;
                }else {
                    h = m - 1;
                }
            }
            return l < n ? letters[l] : letters[0];
        }
    }
    复制代码

    3. 有序数组的 Single Element

    540. Single Element in a Sorted Array (Medium)

    复制代码
    class Solution {
        public int singleNonDuplicate(int[] nums) {
            int l = 0;
            int h = nums.length - 1;
            while(l < h){
                int m = l + (h - l) / 2;
                if(m % 2 == 1) {
                    m--;
                }
                if(nums[m] == nums[m + 1]){
                    l = m + 2;
                } else {
                    h = m;
                }
            }
            return nums[l];
        }
    }
    复制代码

     五、分治

    1. 给表达式加括号

    241. Different Ways to Add Parentheses (Medium)

    复制代码
    class Solution {
        public List<Integer> diffWaysToCompute(String input) {
            List<Integer> ways = new ArrayList<>();
            for(int i = 0; i < input.length();i++){
                char c = input.charAt(i);
                if(c == '+' || c == '-' || c == '*'){
                    List<Integer> left = diffWaysToCompute(input.substring(0,i));
                    List<Integer> right = diffWaysToCompute(input.substring(i + 1));
                    for(int l : left) {
                        for(int r : right) {
                            switch(c) {
                                case '+':
                                ways.add(l + r);
                                break;
                                case '-':
                                ways.add(l - r);
                                break;
                                case '*':
                                ways.add(l * r);
                                break;
                            }
                        }
                    }
                }
            }
            if(ways.size() == 0){
                ways.add(Integer.valueOf(input));
            }
            return ways;
        }
    }
    复制代码

    2. 不同的二叉搜索树

    95. Unique Binary Search Trees II (Medium)

    复制代码
    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public List<TreeNode> generateTrees(int n) {
            if(n < 1) {
                return new LinkedList<TreeNode>();
            }
            return generateSubtrees(1, n);
        }
    
        private List<TreeNode> generateSubtrees(int s, int e) {
            List<TreeNode> res = new LinkedList<TreeNode>();
            if (s > e) {
                res.add(null);
                return res;
            }
            for(int i = s; i <= e; ++i) {
                List<TreeNode> leftSubtrees = generateSubtrees(s, i - 1);
                List<TreeNode> rightSubtrees = generateSubtrees(i + 1, e);
                for (TreeNode left : leftSubtrees) {
                    for (TreeNode right : rightSubtrees){
                        TreeNode root = new TreeNode(i);
                        root.left = left;
                        root.right = right;
                        res.add(root);
                    }
                }
            }
            return res;
        }
    }
    复制代码

     六、搜索

    深度优先搜索和广度优先搜索广泛运用于树和图中,但是它们的应用远远不止如此。

    BFS

    广度优先搜索一层一层地进行遍历,每层遍历都是以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点。需要注意的是,遍历过的节点不能再次被遍历。

    第一层:

    • 0 -> {6,2,1,5}

    第二层:

    • 6 -> {4}
    • 2 -> {}
    • 1 -> {}
    • 5 -> {3}

    第三层:

    • 4 -> {}
    • 3 -> {}

    每一层遍历的节点都与根节点距离相同。设 di 表示第 i 个节点与根节点的距离,推导出一个结论:对于先遍历的节点 i 与后遍历的节点 j,有 di <= dj。利用这个结论,可以求解最短路径等 最优解 问题:第一次遍历到目的节点,其所经过的路径为最短路径。应该注意的是,使用 BFS 只能求解无权图的最短路径,无权图是指从一个节点到另一个节点的代价都记为 1。

    在程序实现 BFS 时需要考虑以下问题:

    • 队列:用来存储每一轮遍历得到的节点;
    • 标记:对于遍历过的节点,应该将它标记,防止重复遍历。

    1. 计算在网格中从原点到特定点的最短路径长度

    1091. Shortest Path in Binary Matrix(Medium)

    复制代码
    class Solution {
        public int shortestPathBinaryMatrix(int[][] grid) {
            if (grid == null || grid.length == 0 || grid[0].length == 0) {
                return -1;
            }
            int[][] direction = {{1,-1}, {1,0}, {1,1}, {0,-1}, {0,1}, {0,1}, {-1,-1}, {-1,0}, {-1,1}};
            int m = grid.length;
            int n = grid[0].length;
            Queue<Pair<Integer, Integer>> queue = new LinkedList<>();
            queue.add(new Pair<>(0, 0));
            int pathLength = 0;
            while (!queue.isEmpty()) {
                int size = queue.size();
                pathLength++;
                while (size-- > 0){
                    Pair<Integer, Integer> cur = queue.poll();
                    int cr = cur.getKey();
                    int cc = cur.getValue();
                    if (grid[cr][cc] == 1) {
                        continue;
                    }
                    if (cr  == m-1 && cc == n-1) {
                        return pathLength;
                    }
                    grid[cr][cc] = 1;
                    for (int[] d:direction) {
                        int nr = cr + d[0];
                        int nc = cc + d[1];
                        if (nr < 0 || nr >= m || nc < 0 || nc >= n) {
                            continue;
                        }
                        queue.add(new Pair<>(nr, nc));
                    }
                }
            }
            return -1;
        }
    }
    复制代码

     查找最大的连通面积

    数字键盘组合

  • 相关阅读:
    bzoj 1071: [SCOI2007]组队
    bzoj 4872: [Shoi2017]分手是祝愿
    (python)循环中动态产生变量
    Python中的exec、eval的区别
    MATLAB中feval与eval的区别
    用intellij idea 写第一个Java程序
    Python词云的中文问题
    python里的apply,applymap和map的区别
    Python 正则表达式匹配小数
    字典的深拷贝与浅拷贝
  • 原文地址:https://www.cnblogs.com/coding-fairyland/p/12622978.html
Copyright © 2011-2022 走看看