Leetcode 第462,474,494,503,513,518,524,538,540,547题(Java解法)

第462题 最少移动次数使数组元素相等 II

给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1。 您可以假设数组的长度最多为10000。

示例 1:

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

解释:只有两个动作是必要的(记得每一步仅可使其中一个元素加1或减1):
[1,2,3] => [2,2,3] => [2,2,2]

解题思路

本题利用排序,然后找中间数,再让每个数减去中间数,得到绝对值,最后相加就是结果。

代码

// 最少移动次数使数组元素相等 II:排序
public class Solution {
    public int minMoves2(int[] nums) {
        Arrays.sort(nums);//排序
        int sum = 0;
        for (int num : nums) {
            sum += Math.abs(nums[nums.length / 2] - num);//计算每一个数减去中位数的绝对值,然后相加
        }
        return sum;
    }
}

时间复杂度为O(nlog n),n为数组长度
空间复杂度为O(log n)

第474题 一和零

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。
请你找出并返回 strs 的最大子集的大小,该子集中 最多 有 m 个 0 和 n 个 1 。
如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

示例 1:

输入输出
strs = [“10”, “0001”, “111001”, “1”, “0”], m = 5, n = 34

解释:最多有 5 个 0 和 3 个 1 的最大子集是 {“10”,“0001”,“1”,“0”} ,因此答案是 4 。
其他满足题意但较小的子集包括 {“0001”,“1”} 和 {“10”,“1”,“0”} 。{“111001”} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

示例 2:

输入输出
strs = [“10”, “0”, “1”], m = 1, n = 12

最大的子集是 {“0”, “1”} ,所以答案是 2 。

解题思路

先利用字符串存储所有字符串中0和1的个数,然后利用动态规划计算减去当前遍历到的字符串后的最大子集个数,最后求得一个满足要求的最大子集个数

代码

// 一和零:动态规划
class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m + 1][n + 1];//存放最大子集个数
        int length = strs.length;
        for (int i = 0; i < length; i++) {
            int[] zerosOnes = getZerosOnes(strs[i]);//获取字符串中的0和1的数量
            int zeros = zerosOnes[0], ones = zerosOnes[1];//建立一个数组存0,一个数组存1
            for (int j = m; j >= zeros; j--) {//
                for (int k = n; k >= ones; k--) {
                    dp[j][k] = Math.max(dp[j][k], dp[j - zeros][k - ones] + 1);//计算减去当前遍历到的字符串中0和1后的最大子集个数,然后加1(当前遍历的子集)
                }
            }
        }
        return dp[m][n];
    }
    public int[] getZerosOnes(String str) {
        int[] zerosOnes = new int[2];
        int length = str.length();
        for (int i = 0; i < length; i++) {
            zerosOnes[str.charAt(i) - '0']++;
        }
        return zerosOnes;
    }
}

时间复杂度为O(lmn+L),l为字符串长度,m,n分别为0和1的容量
空间复杂度为O(mn)

第494题 目标和

给你一个整数数组 nums 和一个整数 target 。
向数组中的每个整数前添加 ‘+’ 或 ‘-’ ,然后串联起所有整数,可以构造一个 表达式 :
例如,nums = [2, 1] ,可以在 2 之前添加 ‘+’ ,在 1 之前添加 ‘-’ ,然后串联起来得到表达式 “+2-1” 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例 1:

输入输出
nums = [1,1,1,1,1], target = 35

解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3

示例 2:

输入输出
nums = [1], target = 11

解题思路

本题使用动态规划,先判断数组各数和是否超过目标值或者各数和减去目标值是否为偶数,然后遍历数组,判断有几个能够满足各数和减去目标值的一半,将次数返回

代码

// 目标和:动态规划
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }//计算所有数字和
        int diff = sum - target;//计算数字和与目标值的差距,如果小于0或者是奇数,则不满足条件
        if (diff < 0 || diff % 2 != 0) {
            return 0;
        }
        int neg = diff / 2;//令neg为差距的一半
        int[] dp = new int[neg + 1];
        dp[0] = 1;
        for (int num : nums) {//遍历数组
            for (int j = neg; j >= num; j--) {//挨个计算是否选用当前数
                dp[j] += dp[j - num];//求得满足neg的所有次数
            }
        }
        return dp[neg];
    }
}

时间复杂度为O(n×(sum−target)),n为数组长,sum为数组各数和,target为目标值
空间复杂度为O(sum−target)

第503题 下一个更大元素 II

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

示例 1:

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

解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

解题思路

利用栈的特性,后进先出,对栈顶元素与当前遍历到的元素进行比值,如果栈顶元素大,则将当前元素入栈,如果栈顶元素小,则将当前栈顶元素在二维数组中的值记为当前元素。如果栈为空,则直接将当前元素入栈。

代码

// 下一个更大元素 II:栈
class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int n = nums.length;
        int[] ret = new int[n];
        Arrays.fill(ret, -1);//先将二维数组的值填入-1
        Deque<Integer> stack = new LinkedList<Integer>();
        for (int i = 0; i < n * 2 - 1; i++) {
            while (!stack.isEmpty() && nums[stack.peek()] < nums[i % n]) {
                ret[stack.pop()] = nums[i % n];//如果栈不为空,且栈顶元素比当前元素小,则将栈顶元素弹出栈,并在数组中将栈顶元素的值标为当前元素值
            }
            stack.push(i % n);//如果栈为空且栈顶元素大于当前元素,则将当前元素入栈
        }
        return ret;
    }
}

时间复杂度为O(n),n为数组长度
空间复杂度为O(n)

第513题 找树左下角的值

给定一个二叉树,在树的最后一行找到最左边的值。

示例 1:

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

示例 2:

输入输出
[1,2,3,4,null,5,6,null,null,7]7

解题思路

利用递归求解,不断递归判断左右节点是否存在,然后另外一个判断递归的深度,利用deep这个值,确保遍历的每一层存的值是最左边的值。

代码

// 找树左下角的值:递归
class Solution {
    private int Deep = -1;
    private int value = 0;
    public int findBottomLeftValue(TreeNode root) {
        value = root.val;
        findLeftValue(root,0);
        return value;
    }
    private void findLeftValue (TreeNode root,int deep) {
        if (root == null) return;
        if (root.left == null && root.right == null) {//如果当前节点的左右节点为空
            if (deep > Deep) {//如果深度比之前的大,则更新value,并将Deep更新为当前深度,这是确保存储当前深度第一个节点
                value = root.val;
                Deep = deep;
            }
        }
        if (root.left != null) findLeftValue(root.left,deep + 1);//如果左节点不为空,则继续递归找左子节点
        if (root.right != null) findLeftValue(root.right,deep + 1);//同上
    }
}

时间复杂度为O(n),n为树的节点数
空间复杂度为O(deep),树的深度

第518题 零钱兑换 II

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。

示例 1:

输入输出
amount = 5, coins = [1, 2, 5]4

解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

示例 2:

输入输出
amount = 3, coins = [2]0

解释:只用面额 2 的硬币不能凑成总金额 3 。

示例 3:

输入输出
amount = 10, coins = [10]1

解题思路

本题使用动态规划,计算每一种硬币组成目标值的可能性。

代码

// 零钱兑换 II:动态规划
class Solution {
    public int change(int amount, int[] coins) {
        int[] dp = new int[amount + 1];
        dp[0] = 1;
        for (int coin : coins) {//遍历所有硬币数
            for (int i = coin; i <= amount; i++) {
                dp[i] += dp[i - coin];//计算使用当前coin能得到i的次数
            }
        }
        return dp[amount];
    }
}

时间复杂度为O(amount×n),amount是总金额,n为coins的长度
空间复杂度为O(amount)

第524题 通过删除字母匹配到字典里最长单词

给你一个字符串 s 和一个字符串数组 dictionary 作为字典,找出并返回字典中最长的字符串,该字符串可以通过删除 s 中的某些字符得到。
如果答案不止一个,返回长度最长且字典序最小的字符串。如果答案不存在,则返回空字符串。

示例 1:

输入输出
s = “abpcplea”, dictionary = [“ale”,“apple”,“monkey”,“plea”]“apple”

示例 2:

输入输出
s = “abpcplea”, dictionary = [“a”,“b”,“c”]“a”

解题思路

本题利用双指针求解,让双指针指向两个字符串首,如果指向的字符相同,则同时向后移一位,如果不相等,则将指向字符串y的指针向后移一位,最后判断是否遍历完了字符串x,然后比较遍历完的字符串长度,将最大长度做为输出。

代码

// 通过删除字母匹配到字典里最长单词:双指针
public class Solution {
    public boolean isSubsequence(String x, String y) {
        int j = 0;
        for (int i = 0; i < y.length() && j < x.length(); i++)
            if (x.charAt(j) == y.charAt(i))//如果两个字符串当前字符匹配,则同时向后移一位,否则移动字符串y
                j++;
        return j == x.length();
    }
    public String findLongestWord(String s, List < String > d) {
        String max_str = "";
        for (String str: d) {//遍历字符数组
            if (isSubsequence(str, s)) {
                if (str.length() > max_str.length() || (str.length() == max_str.length() && str.compareTo(max_str) < 0))//将符合条件的字符串最大长度记录
                    max_str = str;
            }
        }
        return max_str;
    }
}

时间复杂度为O(n*x),x为字符串平均长度,n为数组中的字符串数
空间复杂度为O(x)

第538题 把二叉搜索树转换为累加树

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树

示例 1:

输入输出
[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8][30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

示例 2:

输入输出
root = [0,null,1][1,null,1]

示例 3:

输入输出
root = [1,0,2][3,3,2]

示例 4:

输入输出
root = [3,2,4,1][7,9,4,10]

解题思路

反向中序遍历,先不断遍历右节点,如果没有右节点,则遍历左节点,直到遍历完所有节点。

代码

// 把二叉搜索树转换为累加树:中序遍历
class Solution {
    int sum = 0;
    public TreeNode convertBST(TreeNode root) {
        if (root != null) {
            convertBST(root.right);//不断遍历右节点
            sum += root.val;
            root.val = sum;
            convertBST(root.left);//如果当前节点存在左节点,则遍历左节点
        }
        return root;//实质上是一个反向中序遍历
    }
}

时间复杂度为O(n),n为树的节点数
空间复杂度为O(n)

第540题 有序数组中的单一元素

给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。

示例 1:

输入输出
[1,1,2,3,3,4,4,8,8]2

示例 2:

输入输出
[3,3,7,7,10,11,11]10

解题思路

本题使用二分法,将lo和hi设为数组首尾,计算中间数的位置,如果该位置为奇数,则减1,变成偶数,然后判断该位置与下一位置的值是否相等,如果相等,则单一数在这两个位置之后,因此将lo设在两数后,如果不相等,则说明单一数在两数前,这将hi设为中间数,然后不断判断中间数。

代码

// 有序数组中的单一元素:二分查找
class Solution {
    public int singleNonDuplicate(int[] nums) {
        int lo = 0;
        int hi = nums.length - 1;
        while (lo < hi) {
            int mid = lo + (hi - lo) / 2;
            if (mid % 2 == 1) mid--;//如果中间数是奇数,则将中间数减1
            if (nums[mid] == nums[mid + 1]) {//如果前后相等,则将lo放在这两个数之后
                lo = mid + 2;
            } else {//否则,单一数肯定在中间数之前,则将hi设为中间数
                hi = mid;
            }
        }
        return nums[lo];
    }
}

时间复杂度为O(logn),n为数组大小
空间复杂度为O(1)

第547题 省份数量

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。

示例 1:

输入输出
isConnected = [[1,1,0],[1,1,0],[0,0,1]]2

示例 2:

输入输出
isConnected = [[1,0,0],[0,1,0],[0,0,1]]1

解题思路

使用DFS,首先看当前位置是否为1,如果是则看是否被访问,如果未被访问,则标记为true,然后继续搜寻四周是否有未被访问且为1的位置,不断遍历每一行,最后计算未被访问过且是第一遍访问到的城市数。

代码

// 省份数量:DFS
class Solution {
    public int findCircleNum(int[][] isConnected) {
        int provinces = isConnected.length;
        boolean[] visited = new boolean[provinces];
        int circles = 0;//城市数
        for (int i = 0; i < provinces; i++) {
            if (!visited[i]) {//当前位置未被访问过
                dfs(isConnected, visited, provinces, i);
                circles++;
            }
        }
        return circles;
    }
    public void dfs(int[][] isConnected, boolean[] visited, int provinces, int i) {
        for (int j = 0; j < provinces; j++) {
            if (isConnected[i][j] == 1 && !visited[j]) {//如果当前位置未被访问过,且是1,择将该位置标记为true
                visited[j] = true;
                dfs(isConnected, visited, provinces, j);
            }
        }
    }
}

时间复杂度为O( n 2 n^2 n2),n为城市数
空间复杂度为O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: leetcode高频100java是指LeetCode网站上的100道经典算法目,使用Java语言进行解答。这些目涵盖了各种算法和数据结构,包括数组、链表、树、图、排序、查找、动态规划等等。这些目是程序员面试和算法学习的重要参考资料,也是提高编程能力和解决实际问的有效途径。 ### 回答2: LeetCode是一个著名的程序员面试库,其高频100是指在面试中经常被问到的100道目。这些目涵盖了算法、数据结构、数学等各个领域,是程序员求职和成长过程中不可或缺的练习材料。本文将介绍这100Java解法。 这100覆盖了许多经典算法,如动态规划、贪心算法、双指针等。对于Java程序员来说,最重要的是要掌握这些算法的核心思想及其实现方法。此外,Java核心类库中的一些常用类和函数,如String、Math、Arrays等也是解过程中常用的工具。 对于高频100,需要掌握的核心算法包括二分查找、数组和链表的操作、栈和队列、哈希表、递归等。此外,还需要掌握字符串操作、动态规划、贪心算法、回溯算法、深度/广度优先搜索等经典算法。 以数组和链表为例,需要掌握的操作包括数组的查找、排序和去重,以及链表的遍历、反转和合并等。使用Java语言来实现这些操作时,可以使用Java核心库中的Arrays和Collections类,它们提供了便捷的方法来处理数组和集合。 另外,Java语言还提供了众多数据结构,如栈、队列、双端队列、优先队列、堆等。这些数据结构可以进行复杂的算法操作,如优先队列可以实现贪心算法、堆可以实现堆排序等。Java还提供了Map和Set这两个关键字来实现哈希表的操作,使得开发人员可以轻松地实现哈希表。 最后,Java还提供了众多的工具类和常用函数,例如字符串操作函数、正则表达式、数学函数等。使用这些函数可以为算法提供更加便捷和高效的实现方法。 总之,掌握LeetCode高频100Java解法需要深入理解算法核心思想,灵活使用Java语言的各种工具和函数。在实际练习中,需要注重代码的可读性、复杂度和鲁棒性。 ### 回答3: LeetCode是全球最大的在线练习平台之一,通过解决LeetCode的问,可以帮助人们提高他们的编程能力。在LeetCode上,有许多高频,这些目被认为是最重要的,因为这些目经常在面试中出现。Java作为一种流行的编程语言,被大多数程序员所熟悉和使用。因此,LeetCode高频100java是程序员们需要掌握的重要知识点。接下来,我将详细介绍LeetCode高频100JavaLeetCode高频100java包括许多经典的算法和数据结构问,例如:动态规划、回溯、DFS、BFS、二分查找、排序、链表、栈、队列、树、图等。每个问都有一份完整的Java代码实现,以帮助程序员理解算法思路。不仅如此,Java代码还包括了详细的注释和解释,以帮助程序员更好地掌握算法。 LeetCode高频100java对于Java程序员来说很重要,因为这些目是在日常编码工作和面试中经常出现的问。通过解决这些问,程序员们能够提高他们的编码能力和思维能力。此外,这些问也能帮助程序员们更好地了解Java语言的使用和优化,加深对Java语言特性的理解。 总结来说,对于Java程序员来说,掌握LeetCode高频100java非常重要。这将帮助他们提高他们的编程水平,了解更多的算法和数据结构。通过解决这些问,他们将更容易通过面试,获得更好的编程工作。因此,Java程序员们应该花费足够的时间和精力去学习和掌握LeetCode高频100java

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值