怒刷LeetCode的第18天(Java版)

news2024/11/24 21:02:52

目录

第一题

题目来源

题目内容

解决方法

方法一:置换

方法二:哈希集合

方法三:递归

第二题

题目来源

题目内容

解决方法

方法一:双指针法

方法二:动态规划

方法三:栈

方法四:两边扫描

方法五:单调栈

第三题

题目来源

题目内容

解决方法

方法一:两层循环

方法二:模拟手工乘法

方法三:BigInteger类



第一题

题目来源

41. 缺失的第一个正数 - 力扣(LeetCode)

题目内容

解决方法

方法一:置换

要找到未排序整数数组中缺失的最小正整数,可以使用一种"置换"的思路来解决。

  1. 首先,我们对数组进行遍历,将所有非正整数和大于数组长度的数置为一个特定的值,比如n+1。这是因为我们关心的是在1到n之间的正整数。
  2. 接下来,再次遍历数组,对于每个正整数x,我们将位置x-1上的数字标记为负数。标记的方式是取绝对值并且改变符号。这样做的目的是通过标记来记录该位置上的正整数是否存在。
  3. 最后,我们再次遍历数组,如果某个位置上的数字仍为正数,说明该位置上的正整数缺失。我们返回该位置的索引+1作为结果。
  4. 如果数组中所有位置上的数字都被标记成了负数,说明1到n这个范围内的所有正整数都存在,那么缺失的最小正整数就是n+1。
class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        
        // 将所有非正整数置为n+1
        for (int i = 0; i < n; i++) {
            if (nums[i] <= 0) {
                nums[i] = n + 1;
            }
        }
        
        // 对于每个正整数x,将位置x-1上的数字置为负数
        for (int i = 0; i < n; i++) {
            int num = Math.abs(nums[i]);
            if (num <= n) {
                nums[num - 1] = -Math.abs(nums[num - 1]);
            }
        }
        
        // 返回第一个位置上仍为正数的索引+1
        for (int i = 0; i < n; i++) {
            if (nums[i] > 0) {
                return i + 1;
            }
        }
        
        // 如果都为负数,则返回n+1
        return n + 1;
    }
}

复杂度分析:

首先,让我们逐步分析算法的复杂度:

  • 第一个循环遍历数组,将非正整数置为特定值(n+1),时间复杂度为O(n)。
  • 第二个循环遍历数组,将每个正整数对应位置上的数字标记为负数,时间复杂度为O(n)。
  • 第三个循环遍历数组,查找第一个仍为正数的位置,时间复杂度为O(n)。

因此,整体算法的时间复杂度为O(n)。

在空间复杂度方面,我们只使用了常数级别的额外空间来存储一些临时变量,所以空间复杂度为O(1),即常数级别的额外空间。

综上所述,这个解决方案的时间复杂度是O(n),空间复杂度是O(1)。

LeetCode运行结果:

方法二:哈希集合

除了置换的思路,还可以使用哈希集合来解决这个问题。

这个解决方案首先将数组中小于等于0的数置为大于n的数(无效数),然后创建一个哈希集合,用于存储1到n范围内的正整数。接着,遍历数组,将数组中的正整数加入哈希集合。

最后,遍历1到n的每个数字,找到第一个不在哈希集合中的正整数。如果1到n都在哈希集合中,则返回n+1作为结果。

import java.util.HashSet;

class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        
        // 将数组中小于等于0的数置为大于n的数(无效数)
        for (int i = 0; i < n; i++) {
            if (nums[i] <= 0) {
                nums[i] = n + 1;
            }
        }
        
        // 创建一个哈希集合,用于存储正整数
        HashSet<Integer> set = new HashSet<>();
        
        // 将数组中的正整数加入哈希集合
        for (int i = 0; i < n; i++) {
            if (nums[i] <= n) {
                set.add(nums[i]);
            }
        }
        
        // 遍历1到n,找到第一个不在哈希集合中的正整数
        for (int i = 1; i <= n; i++) {
            if (!set.contains(i)) {
                return i;
            }
        }
        
        // 如果1到n都在哈希集合中,则返回n+1
        return n + 1;
    }
}

复杂度分析:

我们来分析一下这个解决方案的复杂度:

  • 第一个循环遍历数组,将非正整数置为特定值,时间复杂度为O(n)。空间复杂度为O(1),因为只使用了常数级别的额外空间。
  • 创建哈希集合并将正整数加入其中,需要遍历数组,时间复杂度为O(n)。空间复杂度为O(n),因为需要使用额外的哈希集合来存储正整数。
  • 第三个循环遍历1到n的每个数字,查找第一个不在哈希集合中的正整数,时间复杂度为O(n)。

因此,整体算法的时间复杂度为O(n),空间复杂度为O(n)。

与置换的方法相比,使用哈希集合的方法在时间复杂度和空间复杂度上都是一样的,但它使用了额外的哈希集合来存储正整数。

LeetCode运行结果:

方法三:递归

除了置换和哈希集合的思路,还可以使用递归的方式来解决这个问题。

这个方法的思路是遍历数组,对于每个正数nums[i],将其放在正确的位置上,即nums[i]-1。使用递归进行交换操作,直到不能交换为止。然后再遍历数组,找到第一个不在正确位置上的数,即为缺失的最小正整数。

class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        
        // 首先处理边界情况,如果数组为空,则结果为1
        if (n == 0) {
            return 1;
        }
        
        // 对于每个正数nums[i],将其放在正确的位置上,即nums[i]-1
        // 这里使用递归进行交换操作,直到不能交换为止
        for (int i = 0; i < n; i++) {
            while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) {
                swap(nums, i, nums[i] - 1);
            }
        }
        
        // 寻找第一个不在正确位置上的数,即为缺失的最小正整数
        for (int i = 0; i < n; i++) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }
        
        // 如果所有数字都在正确位置上,则返回n+1
        return n + 1;
    }
    
    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

复杂度分析:

  • 时间复杂度:在递归方法中,我们使用递归进行交换操作,直到不能交换为止。对于每个正数nums[i],最多需要交换n次才能找到它正确的位置。因此,整个遍历过程的时间复杂度为O(n),其中n是数组的长度。
  • 空间复杂度:递归方法本身并没有使用额外的空间,只是通过交换操作修改了原始数组。因此,递归方法的空间复杂度为O(1),即只使用了常数级别的额外空间。

需要注意的是,递归方法可能会导致栈溢出的问题,因为每次递归调用都会将一部分函数调用信息存储在栈中。

LeetCode运行结果:

第二题

题目来源

42. 接雨水 - 力扣(LeetCode)

题目内容

解决方法

方法一:双指针法

该解法使用双指针法,从数组的两端开始遍历。维护左右两侧的最大高度(初始值为0),然后根据左右两侧的最大高度和当前柱子的高度,计算能接到的雨水量并累加。具体操作如下:

1、使用双指针 left 和 right 分别指向数组的头部和尾部。
2、初始化左侧最大高度 leftMax 和右侧最大高度 rightMax,初始值都为0。
3、当 left < right 时,进行循环:

  • 如果 height[left] < height[right],表示左侧的柱子较矮。若当前高度大于等于左侧最大高度 leftMax,则更新 leftMax,否则计算当前柱子能接到的雨水量(即 leftMax - height[left])并累加到结果中。
  • 如果 height[left] >= height[right],表示右侧的柱子较矮。若当前高度大于等于右侧最大高度 rightMax,则更新 rightMax,否则计算当前柱子能接到的雨水量(即 rightMax - height[right])并累加到结果中。
  • 更新指针:向内移动高度较低的那个指针(即左侧指针 left 向右移动或右侧指针 right 向左移动)。

4、最后,返回累加得到的雨水量作为结果。

class Solution {
    public int trap(int[] height) {
        int n = height.length;
        if (n == 0) {
            return 0;
        }
        
        int left = 0, right = n - 1;
        int leftMax = 0, rightMax = 0;
        int ans = 0;
        
        while (left < right) {
            // 如果左边的高度小于右边的高度
            if (height[left] < height[right]) {
                // 更新左侧最大高度
                if (height[left] >= leftMax) {
                    leftMax = height[left];
                } else {
                    // 累加雨水量
                    ans += leftMax - height[left];
                }
                left++;
            }
            // 如果左边的高度大于等于右边的高度
            else {
                // 更新右侧最大高度
                if (height[right] >= rightMax) {
                    rightMax = height[right];
                } else {
                    // 累加雨水量
                    ans += rightMax - height[right];
                }
                right--;
            }
        }
        
        return ans;
    }
}

复杂度分析:

  • 时间复杂度:该算法只需要遍历一遍数组,因此时间复杂度是 O(n),其中 n 是数组的长度。
  • 空间复杂度:该算法只需要常数级别的额外空间,因此空间复杂度是 O(1)。

LeetCode运行结果:

方法二:动态规划

除了双指针法之外,还可以使用动态规划来解决这个问题。

该解法使用两个数组 leftMaxrightMax 分别存储每个位置左侧和右侧的最大高度。具体操作如下:

  • 创建两个长度为 n 的数组 leftMax 和 rightMax
  • 初始化 leftMax[0] = height[0] 和 rightMax[n-1] = height[n-1],即第一个位置和最后一个位置的最大高度分别是自身的高度。
  • 计算每个位置左侧的最大高度:
    • 从位置 1 开始遍历到位置 n-1
    • 对于每个位置 ileftMax[i] 是 leftMax[i-1] 和 height[i] 中的较大值。
  • 计算每个位置右侧的最大高度:
    • 从位置 n-2 开始倒序遍历到位置 0。
    • 对于每个位置 irightMax[i] 是 rightMax[i+1] 和 height[i] 中的较大值。
  • 初始化结果变量 ans = 0
  • 遍历每个位置,计算每个位置能接到的雨水量:
    • 对于每个位置 i,能接到的雨水量是 Math.min(leftMax[i], rightMax[i]) - height[i]
    • 将计算得到的雨水量累加到结果变量 ans 中。
  • 返回结果变量 ans 作为答案。
class Solution {
    public int trap(int[] height) {
        int n = height.length;
        if (n == 0) {
            return 0;
        }
        
        int[] leftMax = new int[n]; // 存储每个位置左侧的最大高度
        int[] rightMax = new int[n]; // 存储每个位置右侧的最大高度
        leftMax[0] = height[0];
        rightMax[n-1] = height[n-1];
        
        // 计算每个位置左侧的最大高度
        for (int i = 1; i < n; i++) {
            leftMax[i] = Math.max(leftMax[i-1], height[i]);
        }
        
        // 计算每个位置右侧的最大高度
        for (int i = n - 2; i >= 0; i--) {
            rightMax[i] = Math.max(rightMax[i+1], height[i]);
        }
        
        int ans = 0;
        // 计算每个位置能接到的雨水量
        for (int i = 0; i < n; i++) {
            ans += Math.min(leftMax[i], rightMax[i]) - height[i];
        }
        
        return ans;
    }
}

复杂度分析:

  • 时间复杂度:该算法需要进行三次遍历,分别是计算每个位置左侧的最大高度、计算每个位置右侧的最大高度以及计算每个位置能接到的雨水量。每次遍历都需要遍历整个数组,因此时间复杂度是 O(n),其中 n 是数组的长度。
  • 空间复杂度:该算法使用了两个额外的数组 leftMax 和 rightMax,它们的长度都是 n,因此空间复杂度是 O(n)。除此之外,还需要使用常数级别的额外空间来存储一些临时变量,因此总体的空间复杂度也是 O(n)。

LeetCode运行结果:

方法三:栈

除了双指针法和动态规划,还可以使用栈来解决这个问题。

该解法使用栈来存储数组的索引,栈中的元素按照递减的方式存储。具体操作如下:

  • 初始化结果变量 ans = 0 和一个空栈 stack,用于存储数组的索引。
  • 遍历每个位置 i,对于每个位置:
    • 如果栈不为空且当前位置的高度大于栈顶位置的高度,则说明可以形成一个凹槽。
    • 循环弹出栈顶位置 top,直到栈为空或者当前位置的高度小于等于栈顶位置的高度。
    • 如果栈为空,表示无法形成凹槽,结束循环。
    • 计算当前位置和新栈顶位置之间的距离 distance
    • 计算凹槽的高度 boundedHeight,即当前位置和新栈顶位置的高度的最小值减去弹出的栈顶位置的高度。
    • 更新结果变量,累加凹槽的面积,即 ans += distance * boundedHeight
    • 将当前位置入栈。
  • 返回结果变量 ans 作为答案。
class Solution {
    public int trap(int[] height) {
        int n = height.length;
        if (n == 0) {
            return 0;
        }
        
        int ans = 0; // 存储结果
        Stack<Integer> stack = new Stack<>(); // 存储数组索引
        
        // 遍历每个位置
        for (int i = 0; i < n; i++) {
            // 如果当前位置的高度大于栈顶位置的高度,则可以形成凹槽
            while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
                int top = stack.pop(); // 弹出栈顶位置
                if (stack.isEmpty()) {
                    break; // 栈为空,无法形成凹槽
                }
                
                int distance = i - stack.peek() - 1; // 计算距离
                int boundedHeight = Math.min(height[i], height[stack.peek()]) - height[top]; // 计算高度
                
                ans += distance * boundedHeight; // 更新结果
            }
            
            stack.push(i); // 将当前位置入栈
        }
        
        return ans;
    }
}

复杂度分析:

  • 时间复杂度:该算法只需要对数组进行一次遍历,每个位置的入栈和出栈操作都是常数时间复杂度。因此,时间复杂度为 O(n),其中 n 是数组的长度。
  • 空间复杂度:该算法使用了一个栈来存储索引,最坏情况下栈的大小会达到数组的长度,因此空间复杂度为 O(n)。除此之外,还需要使用常数级别的额外空间来存储一些临时变量,因此总体的空间复杂度也是 O(n)。

LeetCode运行结果:

方法四:两边扫描

除了双指针法、动态规划和使用栈,还可以采用两边扫描的方法来解决这个问题。

该解法使用两个指针 leftright 分别指向数组的左右边界,以及两个变量 leftMaxrightMax 分别保存左侧和右侧的最大高度。

具体操作如下:

  • 初始化结果变量 ans = 0
  • 使用两个指针 left 和 right 分别指向数组的左右边界。
  • 使用两个变量 leftMax 和 rightMax 初始化为 0,分别表示左侧和右侧的最大高度。
  • 当 left 小于 right 时,进行循环:
    • 如果 height[left] < height[right],说明左侧的高度较小,可以计算左侧位置能够接到的雨水量。
      • 如果当前位置的高度大于 leftMax,则更新 leftMax
      • 否则,计算接到的雨水量并累加到结果变量 ans 中。
      • 将 left 向右移动一位。
    • 否则,说明右侧的高度较小,可以计算右侧位置能够接到的雨水量。
      • 如果当前位置的高度大于 rightMax,则更新 rightMax
      • 否则,计算接到的雨水量并累加到结果变量 ans 中。
      • 将 right 向左移动一位。
  • 循环结束后,返回结果变量 ans 作为答案。
class Solution {
    public int trap(int[] height) {
        int n = height.length;
        if (n == 0) {
            return 0;
        }
        
        int ans = 0;
        int left = 0; // 左边界
        int right = n - 1; // 右边界
        int leftMax = 0; // 左侧最大高度
        int rightMax = 0; // 右侧最大高度
        
        while (left < right) {
            if (height[left] < height[right]) {
                // 计算左侧位置能够接到的雨水量
                if (height[left] > leftMax) {
                    leftMax = height[left];
                } else {
                    ans += leftMax - height[left];
                }
                left++;
            } else {
                // 计算右侧位置能够接到的雨水量
                if (height[right] > rightMax) {
                    rightMax = height[right];
                } else {
                    ans += rightMax - height[right];
                }
                right--;
            }
        }
        
        return ans;
    }
}

复杂度分析:

  • 时间复杂度:算法需要进行一次遍历来计算能够接到的雨水量,因此时间复杂度为 O(n),其中 n 是数组的长度。
  • 空间复杂度:算法只使用了常数级别的额外空间来存储变量,因此空间复杂度为 O(1)。不会随着输入规模的增加而增长。

LeetCode运行结果:

方法五:单调栈

除了上述四种常见的解法,还有一种基于单调栈的解法。

具体思路如下:

  1. 使用一个栈来保存数组的下标,栈中的元素满足单调递减的顺序,即栈底的元素是最大的。
  2. 对于数组中的每个位置,进行如下操作:
    1. 如果栈为空或者当前位置的高度小于等于栈顶位置的高度,将当前位置的下标入栈。
    2. 否则,说明当前位置的高度高于栈顶位置的高度,可以计算栈顶位置能够接到的雨水量。
      1. 弹出栈顶元素,并将其作为当前位置的左侧边界。
      2. 如果栈非空,则当前位置的右侧边界是栈顶元素;否则,右侧边界不存在。
      3. 计算栈顶元素和当前位置之间的雨水量,并累加到结果变量中。
      4. 重复步骤 2,直到当前位置的高度小于等于栈顶位置的高度。
  3. 循环结束后,返回结果变量即可。
class Solution {
    public int trap(int[] height) {
        int n = height.length;
        if (n == 0) {
            return 0;
        }

        int ans = 0;
        Stack<Integer> stack = new Stack<>();

        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
                int top = stack.pop();
                if (!stack.isEmpty()) {
                    int left = stack.peek();
                    int width = i - left - 1;
                    int heightDiff = Math.min(height[left], height[i]) - height[top];
                    ans += width * heightDiff;
                }
            }
            stack.push(i);
        }

        return ans;
    }
}

其中 stack 是一个栈,用于保存数组中的下标。变量 ans 初始值为 0,用于累计能够接到的雨水量。

对于数组中的每个位置,如果栈为空或者当前位置的高度小于等于栈顶位置的高度,则将当前位置的下标入栈;否则,说明当前位置的高度高于栈顶位置的高度,可以计算栈顶位置能够接到的雨水量:

  • 弹出栈顶元素,并将其作为当前位置的左侧边界。
  • 如果栈非空,则当前位置的右侧边界是栈顶元素;否则,右侧边界不存在。
  • 计算栈顶元素和当前位置之间的雨水量,并累加到结果变量中。
  • 重复上述步骤,直到当前位置的高度小于等于栈顶位置的高度。

循环结束后,返回结果变量即可。

复杂度分析:

  • 时间复杂度:算法需要对数组进行一次遍历,每个元素最多入栈和出栈一次,因此时间复杂度为 O(n),其中 n 是数组的长度。
  • 空间复杂度:算法使用了一个栈来保存数组的下标,栈的最大长度不超过数组的长度,因此空间复杂度为 O(n)。

总结:基于单调栈的解法在时间复杂度和空间复杂度上都是 O(n)。

LeetCode运行结果:

第三题

题目来源

43. 字符串相乘 - 力扣(LeetCode)

题目内容

解决方法

方法一:两层循环

该问题的解决方案如下:

  1. 定义一个长度为 m + n 的数组 res,用于保存乘积的结果,其中 m 和 n 分别是 num1 和 num2 的长度。
  2. 从右往左遍历 num1 的每一位,用变量 x 表示当前位的数值。
  3. 再从右往左遍历 num2 的每一位,用变量 y 表示当前位的数值。
  4. 将 x 和 y 相乘的结果加到 res 数组的对应位置上,并考虑进位。
  5. 最后,遍历 res 数组进行进位操作,将每一位超过10的部分进位到高位。
  6. 根据进位后的 res 数组构建最终的字符串结果。
  7. 需要注意的是,在最终的字符串结果中,要排除前导零。
class Solution {
    public String multiply(String num1, String num2) {
        int m = num1.length();
        int n = num2.length();
        int[] res = new int[m + n];

        for (int i = m - 1; i >= 0; i--) {
            int x = num1.charAt(i) - '0';
            for (int j = n - 1; j >= 0; j--) {
                int y = num2.charAt(j) - '0';
                res[i + j + 1] += x * y;
            }
        }

        for (int i = m + n - 1; i > 0; i--) {
            res[i - 1] += res[i] / 10;
            res[i] %= 10;
        }

        StringBuilder sb = new StringBuilder();
        int index = 0;
        while (index < m + n && res[index] == 0) {
            index++;
        }
        while (index < m + n) {
            sb.append(res[index]);
            index++;
        }
        
        return sb.length() == 0 ? "0" : sb.toString();
    }
}

复杂度分析:

时间复杂度分析:

在该算法中,我们使用了两重循环来计算乘法以及进行进位操作。其中,外层循环遍历了 num1 的每一位,内层循环遍历了 num2 的每一位。

假设 num1 的长度为 m,num2 的长度为 n。

  • 外层循环的时间复杂度为 O(m)。
  • 内层循环的时间复杂度为 O(n)。

因此,整个算法的时间复杂度为 O(m * n)。

空间复杂度分析:

在该算法中,我们使用了一个额外的数组 res 来保存乘法的结果,其长度为 m + n。

因此,整个算法的空间复杂度为 O(m + n)。

需要注意的是,最终的字符串结果需要消除前导零,但是在最坏的情况下,结果字符串的长度可能达到 m + n。因此,在构建最终结果字符串时,可能需要额外的 O(m + n) 的空间。

综上所述,该算法的时间复杂度为 O(m * n),空间复杂度为 O(m + n)。

LeetCode运行结果:

方法二:模拟手工乘法

除了使用两层循环之外,还可以通过模拟手工乘法的方式实现。

具体步骤如下:

  1. 首先判断两个数中是否有一个为零,如果有,则直接返回结果 "0"。
  2. 初始化结果数组 res,长度为 m + n,其中 m 和 n 分别是 num1 和 num2 的长度。
  3. 从右往左遍历 num1 的每一位数字,用变量 x 表示当前位的数值。
  4. 再从右往左遍历 num2 的每一位数字,用变量 y 表示当前位的数值。
  5. 将 x 和 y 相乘的结果加到 res 数组的对应位置上,即 res[i + j + 1] += x * y。
  6. 在第二次遍历 res 数组时,从右往左进行进位操作,将每一位超过10的部分进位到高位,即 res[i - 1] += res[i] / 10,并将当前位取模,即 res[i] %= 10。
  7. 根据进位后的 res 数组构建最终的字符串结果。
  8. 需要注意的是,在最终的字符串结果中,要排除前导零。

这种方法相较于两层循环的方法,少了一层循环,但是仍然需要进行进位操作。

class Solution {
    public String multiply(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }

        int m = num1.length();
        int n = num2.length();
        int[] res = new int[m + n];

        for (int i = m - 1; i >= 0; i--) {
            int x = num1.charAt(i) - '0';
            for (int j = n - 1; j >= 0; j--) {
                int y = num2.charAt(j) - '0';
                res[i + j + 1] += x * y;
            }
        }

        for (int i = m + n - 1; i > 0; i--) {
            res[i - 1] += res[i] / 10;
            res[i] %= 10;
        }

        StringBuilder sb = new StringBuilder();
        int index = res[0] == 0 ? 1 : 0;
        while (index < m + n) {
            sb.append(res[index]);
            index++;
        }

        return sb.toString();
    }
}

复杂度分析:

时间复杂度分析:

  • 遍历 num1 的每一位数字的过程需要进行 m 次循环。
  • 对于每一次 num1 的遍历,又需要遍历 num2 的每一位数字,共进行了 n 次循环。
  • 在每次循环中,进行了常数次的乘法操作和加法操作,所以每次循环的时间复杂度为 O(1)。
  • 因此,总体上,该算法的时间复杂度为 O(m * n)。

空间复杂度分析:

  • 初始化了一个结果数组 res,长度为 m + n,需要额外的空间存储计算结果,所以空间复杂度为 O(m + n)。
  • 同时,还使用了若干个变量用于存储中间结果,这些变量是常数级别的,不随输入规模的增大而增大,可以忽略不计。
  • 因此,总体上,该算法的空间复杂度为 O(m + n)。

需要注意的是,以上复杂度分析是基于输入字符串的长度进行的。在实际应用中,该算法的性能通常是可以接受的,因为字符串长度一般不会非常大。但如果字符串的长度非常巨大,可能会导致算法的运行时间较长。

LeetCode运行结果:

方法三:BigInteger类

除了两层循环,模拟手工乘法的方法外,还可以使用Java的BigInteger类来实现字符串相乘。

BigInteger类是Java中用于处理任意精度整数的类,可以支持很大范围的整数运算。使用BigInteger类,可以简化字符串相乘的过程。

import java.math.BigInteger;
class Solution {
    public String multiply(String num1, String num2) {
    BigInteger n1 = new BigInteger(num1);
    BigInteger n2 = new BigInteger(num2);
    BigInteger result = n1.multiply(n2);
    
    return result.toString();
    }
}

以上代码直接使用BigInteger类创建两个BigInteger对象n1和n2,分别对应num1和num2。然后使用multiply方法计算它们的乘积,最后将结果转换为字符串格式返回。

需要注意的是,这种方法利用了BigInteger类的内置函数,因此不符合题目要求"不能使用任何内置的 BigInteger 库或直接将输入转换为整数",但是效率上会更高。

复杂度分析:

假设num1的长度为n1,num2的长度为n2。

  • 时间复杂度:创建BigInteger对象的时间复杂度为O(max(n1, n2)),相乘操作的时间复杂度为O(n1 + n2),因此整体的时间复杂度为O(max(n1, n2))。
  • 空间复杂度:创建了两个BigInteger对象和一个结果对象,因此空间复杂度为O(1)。

LeetCode运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1048799.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字乡村包括哪些方面?数字乡村应用介绍

数字乡村是指利用物联网、数字化和智能化技术&#xff0c;借助现代数字智能产品、高效信息服务和物联网基础设施&#xff0c;以提高农村居民生活质量&#xff0c;助力拓展经济发展前景。 创建数字村庄有助于缩小城乡社区之间的差距&#xff0c;保障每个人都能平等地享受科技发展…

LabVIEW开发低成本静脉监测和控制输液系统

LabVIEW开发低成本静脉监测和控制输液系统 信息技术的使用和进步彻底改变了现代医疗保健的面貌。医院、疗养院和其他姑息治疗院需要不同的人力资源&#xff0c;如医生、技术人员、护士和其他工作人员&#xff0c;他们共同提供最先进的医疗保健。COVID-19大流行表现出严重缺乏此…

安全厂商安恒信息加入龙蜥社区,完成 与 Anolis OS 兼容适配

近日&#xff0c;杭州安恒信息技术股份有限公司&#xff08;以下简称“安恒信息”&#xff09;签署了 CLA&#xff08;Contributor License Agreement&#xff0c;贡献者许可协议&#xff09;&#xff0c;正式加入龙蜥社区&#xff08;OpenAnolis&#xff09;&#xff0c;并成为…

2023-9-27 JZ77 按之字型顺序打印二叉树

题目链接&#xff1a;按之字型顺序打印二叉树 import java.util.*;/** public class TreeNode {* int val 0;* TreeNode left null;* TreeNode right null;* public TreeNode(int val) {* this.val val;* }* }*/public class Solution {/*** 代码中的类名、方…

阿里云服务器企业级独享和共享型有什么区别?

阿里云ECS云服务器共享型和企业级有什么区别&#xff1f;企业级就是独享型&#xff0c;共享型和企业级云的主要区别CPU调度模式&#xff0c;共享型是非绑定CPU调度模式&#xff0c;企业级是固定CPU调度模式&#xff0c;共享型云服务器在高负载时计算性能可能出现波动不稳定&…

恋爱聊天追女神沟通话术小程序开发演示

现在什么最有市场&#xff1f;婚恋、交友、恋爱…… 单身多需求就自然而然的产生了&#xff0c;而且还很大。我们可以搜素查看各平台这类项目的流量&#xff0c;基本都不低。 因此针对细分领域开发两款恋爱聊天沟通话术小程序&#xff0c;一款为本地数据版&#xff0c;一款为…

携手华为使能全场景创新,夯实算力底座,麒麟信安受邀参加华为全联接大会2023

智能化浪潮正奔腾而来&#xff0c;驱动千行百业锚定新航向、跑出加速度。日前&#xff0c;第八届华为全联接大会&#xff08;HUAWEI CONNECT 2023&#xff09;在上海举办。大会邀请思想领袖、商业精英、技术专家、合作伙伴、开发者等业界同仁&#xff0c;从商业、产业、生态等方…

设计模式1、单例模式 Singleton

解释说明&#xff1a;确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问这个唯一实例 要点如下 有且仅有一个实例 必须自行创建自己的唯一实例 必须给所有其他对象提供这一实例 具体实现要点如下 提供一个 private 构造函数&#xff08;防止外部调用而构造类的实例…

还在用 !=null 判空?让我们用Java8的全新API去优化代码吧

当我们编写Java代码时&#xff0c;经常需要处理空值&#xff08;null&#xff09;&#xff0c;因为空值可能导致NullPointerException异常&#xff0c;这是一个常见的运行时异常。在Java 8中&#xff0c;引入了Optional类来更优雅地处理可能为空的值&#xff0c;从而减少NullPo…

NOSQL Redis十大数据类型

String 字符串 string 是redis最基本的类型&#xff0c;而是使用最多的数据类型&#xff0c; 一个 key 对应一个 value string 类型是 二进制安全的&#xff0c;意思reidis 的string 可以包含任何数据&#xff08;任何数据都可以转换binary的&#xff09;&#xff0c;比如jpg图…

推荐一个好用的电商开源项目yudao源码

1、项目下载cloneruoyi-vue-pro: &#x1f525; 官方推荐 &#x1f525; RuoYi-Vue 全新 Pro 版本&#xff0c;优化重构所有功能。基于 Spring Boot MyBatis Plus Vue & Element 实现的后台管理系统 微信小程序&#xff0c;支持 RBAC 动态权限、数据权限、SaaS 多租户、…

使用日志分析工具了解网络情况

日志分析&#xff08;或日志文件分析&#xff09;是检查整个网络中生成的日志数据的过程&#xff0c;日志数据从各种来源生成&#xff0c;包括外围设备、工作站、服务器、应用程序以及其他硬件和软件组件&#xff0c;将它们收集到一个中心位置并进行分析&#xff0c;可以为了解…

提升工作效率的一些网站、应用、插件和小技巧(二)

前言 距离发布提升工作效率的一些网站、应用、插件和小技巧&#xff08;一&#xff09;已经过去了三年&#xff0c;这次再分享一下这三年里新 Get 到的一些工作、技巧&#xff0c;欢迎各位在评论区也分享一下自己使用的工具软件等&#xff0c;也希望下一个三年我还能继续坚持分…

蓝桥杯每日一题2023.9.28

AcWing 4409. 砍竹子 - AcWing 题目描述 题目分析 注&#xff1a;sqrtl的范围为long double&#xff0c;比sqrt更加精确 使用优先队列维护一段区间&#xff0c;如果连续一段相同就合并为一个区间&#xff0c;从大到小去枚举&#xff0c;每次先取出最大的一段&#xff0c;双…

MySQL到TiDB:Hive Metastore横向扩展之路

作者&#xff1a;vivo 互联网大数据团队 - Wang Zhiwen 本文介绍了vivo在大数据元数据服务横向扩展道路上的探索历程&#xff0c;由实际面临的问题出发&#xff0c;对当前主流的横向扩展方案进行了调研及对比测试&#xff0c;通过多方面对比数据择优选择TiDB方案。其次分享了整…

首批48所高校大模型开课“尝鲜”,AI教学赋能计划合作名单公布

为适应大模型时代快速迭代的人才需求&#xff0c;百度飞桨全新发布《AI教学赋能计划&#xff08;大模型特辑&#xff09;》&#xff0c;提供文心大模型、飞桨AI Studio星河社区、大模型课程资源、师资培训、高校竞赛等体系化支持&#xff0c;支持高校顺应时代潮流、共启大模型人…

LeetCode算法二叉树—116. 填充每个节点的下一个右侧节点指针

目录 116. 填充每个节点的下一个右侧节点指针 题解&#xff1a; 代码&#xff1a; 运行结果&#xff1a; 给定一个 完美二叉树 &#xff0c;其所有叶子节点都在同一层&#xff0c;每个父节点都有两个子节点。二叉树定义如下&#xff1a; struct Node {int val;Node *left;N…

爬虫抓取数据时显示超时,是爬虫IP质量问题?

当我们进行网络爬虫开发时&#xff0c;有时会遇到抓取数据时出现超时的情况。这可能是由于目标网站对频繁请求做了限制&#xff0c;或者是由于网络环境不稳定造成的。其中&#xff0c;爬虫IP的质量也是导致超时的一个重要因素。本文将探讨抓取数据时出现超时的原因&#xff0c;…

2023-9-28 JZ54 二叉搜索树的第k个结点

题目链接&#xff1a;二叉搜索树的第k个结点 import java.util.*;/** public class TreeNode {* int val 0;* TreeNode left null;* TreeNode right null;* public TreeNode(int val) {* this.val val;* }* }*/public class Solution {/*** 代码中的类名、方…

什么是大数据可视化

在互联网高速发展的当今&#xff0c;5G的兴起加速了数据传输的速度&#xff1b;与此同时&#xff0c;智能物联网如智慧家电、可穿戴设备等产品的火热&#xff0c;进一步扩充了数据获取的渠道。不仅仅在网页上、手机和电脑应用上以秒计产生海量数据&#xff0c;智能设备同时也在…