zoukankan      html  css  js  c++  java
  • 【LeetCode】 41

    41. 缺失的第一个正数

    给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。

    示例 1:

    输入: [1,2,0]
    输出: 3
    

    示例 2:

    输入: [3,4,-1,1]
    输出: 2
    

    示例 3:

    输入: [7,8,9,11,12]
    输出: 1
    

    提示:

    你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。

    哈希表法

    	// 时间复杂度 O(N) 空间复杂度 O(N)
        public int firstMissingPositive(int[] nums) {
            int n = nums.length;
    
            Set<Integer> set = new HashSet<>();
            for(int num : nums) set.add(num);
            for(int i = 1;  i <= n; i ++){
                if(!set.contains(i)) return i;
            }
            return n + 1;
        }
    

    排序法

        // 时间复杂度 O(Nlog(N)) 空
        public int firstMissingPositive(int[] nums) {
            // 先排序 Nlog(N)
            Arrays.sort(nums);
    
            int pre = 0;
            for(int i = 0; i < nums.length; i ++){
                // 跳过非正整数和重复值
                if(nums[i] <= 0 || nums[i] == pre) continue;
                // 找到第一个突变的元素
                else if(nums[i] > pre + 1) break;
    
                pre ++;
            }
            return pre + 1;
        }
    

    原地哈希法

    	// 时间复杂度 O(N) 空间复杂度 O(1)
        // 原地哈希: 自定义哈希函数 将数值 i 映射到 i - 1的位置上
        public int firstMissingPositive(int[] nums) {
            int len = nums.length;
            for(int i = 0; i < len; i ++){
                // 在指定范围内, 且没有放在正确位置上, 交换
                while(nums[i] > 0 && nums[i] <= len && nums[nums[i] - 1] != nums[i]){
                    swap(nums, nums[i] - 1, i);
                }
            }
            // 找到不符合的位置
            for(int i = 0; i < len; i ++){
                if(nums[i] != i + 1) return i + 1;
            }
            // 都正确则返回数组长度 + 1
            return len + 1;
        }
        void swap(int[] nums, int i, int j){
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
    

    42. 接雨水

    给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

    img

    上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

    示例:

    输入: [0,1,0,2,1,0,1,3,2,1,2,1]
    输出: 6
    

    暴力求解

        // 时间复杂度 O(N^2)
    	public int trap(int[] height) {
            int res = 0;
            // 遍历每一列柱子
            for(int i = 1; i < height.length - 1; i ++){
                // 分别记录当前柱子向左 向右的最大高度
                int leftMax = 0, rightMax = 0;
                for(int j = 0; j <= i; j ++) 
                    leftMax = Math.max(leftMax, height[j]);
                for(int j = i; j < height.length; j ++) 
                    rightMax = Math.max(rightMax, height[j]);
    			// 当前位置 water[i] = min(max(h[0->i], h(i->len-1))) - h[i]
                res += Math.min(leftMax, rightMax) - height[i];
            }
            return res;
        }
    

    动态规划

        // 时间复杂度 优化至 O(N) , 但空间复杂度为 O(N)
    	public int trap(int[] height) {
            if(height.length == 0) return 0;
            int n = height.length;
            // 优化方案: 创建两个备忘录,分别记录leftMax 和 rightMax
            int[] leftMax = new int[n];
            int[] rightMax = new int[n];
            int res = 0;
            // 初始化
            leftMax[0] = height[0];
            rightMax[n - 1] = height[n - 1];
            for(int i = 1; i < n; i ++) 
                leftMax[i] = Math.max(height[i], leftMax[i - 1]);
            for(int i = n - 2; i >= 0; i --) 
                rightMax[i] = Math.max(height[i] , rightMax[i + 1]);
            for(int i = 1; i < n - 1; i ++) 
                res += Math.min(leftMax[i], rightMax[i]) - height[i];
            return res;
        }
    

    双指针

    	// 时间复杂度 O(N) 空间 O(1)
    	// 省去创建备忘录的空间, 边走变算
        public int trap(int[] height) {
            if(height.length == 0) return 0;
            int n = height.length;
            int l = 0, r = height.length - 1, res = 0;
            int leftMax = height[0], rightMax = height[n - 1];
            while(l <= r){
                leftMax = Math.max(leftMax, height[l]);
                rightMax = Math.max(rightMax, height[r]);
                if(leftMax < rightMax) 
                    res += leftMax - height[l ++];
                else 
                    res += rightMax - height[r --];
            }
            return res;
        }
    

    43. 字符串相乘

    给定两个以字符串形式表示的非负整数 num1num2,返回 num1num2 的乘积,它们的乘积也表示为字符串形式。

    示例 1:

    输入: num1 = "2", num2 = "3"
    输出: "6"
    

    示例 2:

    输入: num1 = "123", num2 = "456"
    输出: "56088"
    

    说明:

    1. num1num2 的长度小于110。
    2. num1num2 只包含数字 0-9
    3. num1num2 均不以零开头,除非是数字 0 本身。
    4. 不能使用任何标准库的大数类型(比如 BigInteger)直接将输入转换为整数来处理
    /**
    num1的第i位(高位从0开始)和num2的第j位相乘的结果在乘积中的位置是[i+j, i+j+1]
    例: 123 * 45,  123的第1位 2 和45的第0位 4 乘积 08 存放在结果的第[1, 2]位中
              index:    0 1 2 3 4  
    
                            1 2 3
                        *     4 5
                        ---------
                              1 5
                            1 0
                          0 5
                        ---------
                          0 6 1 5
                            1 2
                          0 8
                        0 4
                        ---------
                        0 5 5 3 5
    这样我们就可以单独都对每一位进行相乘计算把结果存入相应的index中        
    **/
    public String multiply(String num1, String num2) {
        int m = num1.length(), n = num2.length();
        // 记录每位数字的数组
        int[] arr = new int[m + n];
        // 从个位开始计算
        for(int i = m - 1; i >= 0; i --){
            for(int j = n - 1; j >= 0; j --){
                // i+j, i+j+1
                int mul = (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
                int p1 = i + j, p2 = i + j + 1;
                // 本身乘积 + 原来的数
                int sum = mul + arr[p2];
                // 取个位
                arr[p2] = sum % 10;
                // 进位
                arr[p1] += sum / 10;
            }
        }
        // 移除前导零,只需记录第一个非0的位置即可
        int i = 0;
        while(i < arr.length && arr[i] == 0) i ++;
        if(i == arr.length) return "0";
        StringBuilder res = new StringBuilder();
        while(i < arr.length){
            res.append(arr[i++]);
        }
        return res.toString();
    }
    

    44. 通配符匹配

    给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?''*' 的通配符匹配。

    '?' 可以匹配任何单个字符。
    '*' 可以匹配任意字符串(包括空字符串)。
    

    两个字符串完全匹配才算匹配成功。

    说明:

    • s 可能为空,且只包含从 a-z 的小写字母。
    • p 可能为空,且只包含从 a-z 的小写字母,以及字符 ?*

    示例 1:

    输入:
    s = "aa"
    p = "a"
    输出: false
    解释: "a" 无法匹配 "aa" 整个字符串。
    

    示例 2:

    输入:
    s = "aa"
    p = "*"
    输出: true
    解释: '*' 可以匹配任意字符串。
    

    示例 3:

    输入:
    s = "cb"
    p = "?a"
    输出: false
    解释: '?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。
    

    示例 4:

    输入:
    s = "adceb"
    p = "*a*b"
    输出: true
    解释: 第一个 '*' 可以匹配空字符串, 第二个 '*' 可以匹配字符串 "dce".
    

    示例 5:

    输入:
    s = "acdcb"
    p = "a*c?b"
    输出: false
    

    // f[i][j] = 标识 s的 0 - i 与 p的 0 - j 是否匹配
    public boolean isMatch(String s, String p) {
        int m = s.length(), n = p.length();
        boolean[][] f = new boolean[m + 1][n + 1];
    	// 空串匹配
        f[0][0] = true;
    	// s为空,只要p的开头是* 就代表匹配
        for(int j = 1; j <= n; j ++){
            if(p.charAt(j - 1) == '*') f[0][j] = true;
            else break;
        }
    
        for(int i = 1; i <= m; i ++){
            for(int j = 1; j <= n; j ++){
                // f[i][j - 1]的情况 标识 ab和ab*
                // f[i - 1][j]的情况 标识 abcd 和 ab*
                if(p.charAt(j - 1) == '*'){
                    f[i][j] = f[i][j - 1] || f[i - 1][j];
                }else if(p.charAt(j - 1) == '?' || s.charAt(i - 1) == p.charAt(j - 1)){
                    f[i][j] = f[i - 1][j - 1];
                }
            }
        }
        return f[m][n];
    }
    

    45. 跳跃游戏 II

    给定一个非负整数数组,你最初位于数组的第一个位置。

    数组中的每个元素代表你在该位置可以跳跃的最大长度。

    你的目标是使用最少的跳跃次数到达数组的最后一个位置。

    示例:

    输入: [2,3,1,1,4]
    输出: 2
    解释: 跳到最后一个位置的最小跳跃数是 2。
         从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
    

    说明:

    假设你总是可以到达数组的最后一个位置。

    https://leetcode-cn.com/problems/jump-game-ii/solution/45-by-ikaruga/

    贪心算法

        public int jump(int[] nums) {
            int ans = 0, start = 0, end = 1;
            while(end < nums.length){
                int maxPos = 0;
                for(int i = l; i < end; i ++){
                    //能跳到的最远的距离
                    maxPos = Math.max(maxPos, i + nums[i]);
                }
                //下一次起跳点范围开始的格子
                start = end;
                //下一次起跳点范围结束的格子
                end = maxPos + 1;
                ans ++;
            }
            return ans;
        }
    

    46. 全排列

    给定一个 没有重复 数字的序列,返回其所有可能的全排列。

    示例:

    输入: [1,2,3]
    输出:
    [
      [1,2,3],
      [1,3,2],
      [2,1,3],
      [2,3,1],
      [3,1,2],
      [3,2,1]
    ]
    
    class Solution {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        boolean[] used;
        public List<List<Integer>> permute(int[] nums) {
            used = new boolean[nums.length];
            dfs(nums);
            return res;
        }
    
        void dfs(int[] nums){
            if(path.size() == nums.length) {
                res.add(new ArrayList<>(path));
                return;
            }
            for(int i = 0; i < nums.length; i ++){
                if(!used[i]){
                    used[i] = true;
                    path.add(nums[i]);
                    dfs(nums);
                    path.remove(path.size() - 1);
                    used[i] = false;
                }
            }
        }
    }
    

    47. 全排列 II

    给定一个可包含重复数字的序列,返回所有不重复的全排列。

    示例:

    输入: [1,1,2]
    输出:
    [
      [1,1,2],
      [1,2,1],
      [2,1,1]
    ]
    

    https://leetcode-cn.com/problems/permutations-ii/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liwe-2/

    我们需要明确,在这个DFS的过程中,哪里出现了重复?在这个图中,已经十分明显地看到:

    • 这次搜索的起点和上次的起点相同 , visited[i - 1] == visited[i]。
    • 且上一次的数已经被撤销,visited[i-1] ==false。

    为保证i-1不越界,加上i>0的条件:

    if (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]) {
        continue;
    }
    
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        boolean[] visited;
        public List<List<Integer>> permuteUnique(int[] nums) {
            visited = new boolean[nums.length];
            Arrays.sort(nums); //保证数组的有序性
            dfs(nums);
            return res;
        }
        
        void dfs(int[]nums){
            if(path.size() == nums.length) {
                res.add(new ArrayList<>(path));
                return;
            }
            for(int i = 0; i < nums.length ; i++){
                if( visited[i]) continue;
                if( i > 0 && nums[i] == nums[i - 1]  && !visited[i - 1]) continue; //此处剪枝
                visited[i] = true;
                path.add(nums[i]);
                dfs(nums);
                visited[i] = false;
                path.remove(path.size()-1);
            }
        }
    

    48. 旋转图像

    给定一个 n × n 的二维矩阵表示一个图像。

    将图像顺时针旋转 90 度。

    说明:

    你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。

    示例 1:

    给定 matrix = 
    [
      [1,2,3],
      [4,5,6],
      [7,8,9]
    ],
    
    原地旋转输入矩阵,使其变为:
    [
      [7,4,1],
      [8,5,2],
      [9,6,3]
    ]
    

    示例 2:

    给定 matrix =
    [
      [ 5, 1, 9,11],
      [ 2, 4, 8,10],
      [13, 3, 6, 7],
      [15,14,12,16]
    ], 
    
    原地旋转输入矩阵,使其变为:
    [
      [15,13, 2, 5],
      [14, 3, 4, 1],
      [12, 6, 8, 9],
      [16, 7,10,11]
    ]
    
        public void rotate(int[][] matrix) {
            int n = matrix.length;
    
            //转置
            /*
             1 2 3  --> 1 4 7
             4 5 6  --> 2 5 8
             7 8 9  --> 3 6 9
            */
            for(int i = 0; i < n; i ++){
                for(int j = i; j < n; j ++){
                    swap(matrix, i, j, j, i);
                }
            }
            /*
             1 4 7  --> 7 4 1
             2 5 8  --> 8 5 2
             3 6 9  --> 9 6 3
            */
            for(int i = 0; i < n; i ++){
                for(int j = 0; j < n / 2; j ++){
                    swap(matrix, i, j, i, n - j - 1);
                }
            }
        }
        void swap(int[][] m, int i1, int j1, int i2, int j2){
            int temp = m[i1][j1];
            m[i1][j1] = m[i2][j2];
            m[i2][j2] = temp;
        }
    

    49. 字母异位词分组

    给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

    示例:

    输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
    输出:
    [
      ["ate","eat","tea"],
      ["nat","tan"],
      ["bat"]
    ]
    

    说明:

    • 所有输入均为小写字母。
    • 不考虑答案输出的顺序。
        public List<List<String>> groupAnagrams(String[] strs) {
            //O(N KlogK) N = strs.length  K = str.length()
            if(strs.length == 0) return new ArrayList<>();
            Map<String, List> hash = new HashMap<>();
    
            for(String str : strs){
                // 字符排序
                char[] chs = str.toCharArray();
                Arrays.sort(chs);
                String key = new String(chs);
                if(!hash.containsKey(key)) hash.put(s, new ArrayList<List>());
                hash.get(key).add(str);
            }
            return new ArrayList(hash.values());
        }
    

    50. Pow(x, n)

    实现 pow(x, n) ,即计算 x 的 n 次幂函数。

    示例 1:

    输入: 2.00000, 10
    输出: 1024.00000
    

    示例 2:

    输入: 2.10000, 3
    输出: 9.26100
    

    示例 3:

    输入: 2.00000, -2
    输出: 0.25000
    解释: 2-2 = 1/22 = 1/4 = 0.25
    

    说明:

    • -100.0 < x < 100.0
    • n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。

    https://leetcode-cn.com/problems/powx-n/solution/50-powx-n-kuai-su-mi-qing-xi-tu-jie-by-jyd/

        public double myPow(double x, int n) {
            if(x == 0.0f) return 0.0d;
            long b = n;
            double res = 1.0;
            // 当n < 0时,转化为 n >= 0的情况
            if(b < 0){
                x = 1 / x;
                b = -b;
            }
            while(b > 0){
                if((b & 1) == 1) // b % 2 == 1
                    res *= x;
                x *= x; // x = x ^ 2
                b >>= 1; // b = b // 2
            }
            return res;
        }
    
  • 相关阅读:
    nginxWebUI
    c#通过串口及CAN模块实现上位及下位机通讯
    使用IDEA创建SpringBoot项目出现intellij idea No active profile set, falling back to default profiles: default
    linux服务器创建python环境
    在Linux服务器上安装anaconda
    牛客-小w的魔术扑克【并查集】
    bzoj#4161-Shlw loves matrixI【常系数线性齐次递推】
    CF903G-Yet Another Maxflow Problem【线段树,最大流】
    P4700-[CEOI2011]Traffic【tarjan,dp】
    CF1039D-You Are Given a Tree【根号分治,贪心】
  • 原文地址:https://www.cnblogs.com/summerday152/p/13780942.html
Copyright © 2011-2022 走看看