leetcode
leetcode 2751 ~ 2800
将元素分配到两个数组中 II

将元素分配到两个数组中 II

难度:

标签:

题目描述

You are given a 1-indexed array of integers nums of length n.

We define a function greaterCount such that greaterCount(arr, val) returns the number of elements in arr that are strictly greater than val.

You need to distribute all the elements of nums between two arrays arr1 and arr2 using n operations. In the first operation, append nums[1] to arr1. In the second operation, append nums[2] to arr2. Afterwards, in the ith operation:

  • If greaterCount(arr1, nums[i]) > greaterCount(arr2, nums[i]), append nums[i] to arr1.
  • If greaterCount(arr1, nums[i]) < greaterCount(arr2, nums[i]), append nums[i] to arr2.
  • If greaterCount(arr1, nums[i]) == greaterCount(arr2, nums[i]), append nums[i] to the array with a lesser number of elements.
  • If there is still a tie, append nums[i] to arr1.

The array result is formed by concatenating the arrays arr1 and arr2. For example, if arr1 == [1,2,3] and arr2 == [4,5,6], then result = [1,2,3,4,5,6].

Return the integer array result.

 

Example 1:

Input: nums = [2,1,3,3]
Output: [2,3,1,3]
Explanation: After the first 2 operations, arr1 = [2] and arr2 = [1].
In the 3rd operation, the number of elements greater than 3 is zero in both arrays. Also, the lengths are equal, hence, append nums[3] to arr1.
In the 4th operation, the number of elements greater than 3 is zero in both arrays. As the length of arr2 is lesser, hence, append nums[4] to arr2.
After 4 operations, arr1 = [2,3] and arr2 = [1,3].
Hence, the array result formed by concatenation is [2,3,1,3].

Example 2:

Input: nums = [5,14,3,1,2]
Output: [5,3,1,2,14]
Explanation: After the first 2 operations, arr1 = [5] and arr2 = [14].
In the 3rd operation, the number of elements greater than 3 is one in both arrays. Also, the lengths are equal, hence, append nums[3] to arr1.
In the 4th operation, the number of elements greater than 1 is greater in arr1 than arr2 (2 > 1). Hence, append nums[4] to arr1.
In the 5th operation, the number of elements greater than 2 is greater in arr1 than arr2 (2 > 1). Hence, append nums[5] to arr1.
After 5 operations, arr1 = [5,3,1,2] and arr2 = [14].
Hence, the array result formed by concatenation is [5,3,1,2,14].

Example 3:

Input: nums = [3,3,3,3]
Output: [3,3,3,3]
Explanation: At the end of 4 operations, arr1 = [3,3] and arr2 = [3,3].
Hence, the array result formed by concatenation is [3,3,3,3].

 

Constraints:

  • 3 <= n <= 105
  • 1 <= nums[i] <= 109

代码结果

运行时间: 633 ms, 内存: 41.9 MB


/*
 * 思路:
 * 1. 创建一个函数 greaterCount 用于计算数组中严格大于给定值的元素数量。
 * 2. 初始化两个数组 arr1 和 arr2,分别用于存储 nums 的元素。
 * 3. 遍历 nums 数组,根据条件将元素添加到 arr1 或 arr2。
 * 4. 最后将 arr1 和 arr2 连接起来形成结果数组并返回。
 */

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class SolutionStream {
    public int[] divideAndMerge(int[] nums) {
        List<Integer> arr1 = new ArrayList<>();
        List<Integer> arr2 = new ArrayList<>();
        
        for (int i = 0; i < nums.length; i++) {
            if (i % 2 == 0) {
                arr1.add(nums[i]);
            } else {
                arr2.add(nums[i]);
            }
            if (i >= 2) {
                long count1 = greaterCount(arr1, nums[i]);
                long count2 = greaterCount(arr2, nums[i]);
                if (count1 > count2) {
                    arr1.add(nums[i]);
                } else if (count1 < count2) {
                    arr2.add(nums[i]);
                } else {
                    if (arr1.size() <= arr2.size()) {
                        arr1.add(nums[i]);
                    } else {
                        arr2.add(nums[i]);
                    }
                }
            }
        }
        
        return IntStream.concat(arr1.stream().mapToInt(i -> i), arr2.stream().mapToInt(i -> i)).toArray();
    }

    private long greaterCount(List<Integer> arr, int val) {
        return arr.stream().filter(num -> num > val).count();
    }
}

解释

方法:

该题解采用了二进制索引树(Binary Indexed Tree,BIT)来高效地维护和查询数组中特定值的计数信息。首先,创建一个值到索引的映射(v2i),将数组中的元素映射到一个连续的索引范围内,并按值排序。这个映射用于在BIT中更新和查询位置。对于数组中的每个元素,基于其在BIT中的计数值以及当前两个数组(arr1和arr2)的长度,决定将元素添加到哪一个数组。使用BIT可以快速计算出任意元素值大于当前元素值的元素数量。这种方法允许我们在对数时间内处理每个元素的插入操作,从而有效地解决问题。

时间复杂度:

O(n log m)

空间复杂度:

O(m + n)

代码细节讲解

🦆
在解决方法中提到使用了二进制索引树(BIT),这种数据结构具体是如何帮助解决这个问题的?
二进制索引树(Binary Indexed Tree,BIT),也被称为树状数组,主要用于高效地处理数组的前缀和查询和更新操作。在本题中,BIT 被用于维护和查询数组元素的计数信息。通过BIT,可以快速计算出任意给定元素值大于当前元素值的元素数量,这是通过在每次添加元素到数组时更新BIT,并在需要时查询所有大于当前元素的索引的计数总和来实现的。这样,每次元素插入的处理时间能够保持在对数级别(O(log n)),从而使整体解决方案更加高效。
🦆
题解中提到的`值到索引的映射(v2i)`是如何构建的,为什么需要将数组中的元素映射到一个连续的索引范围内?
值到索引的映射(v2i)是通过将数组中的所有不同元素进行排序和去重后,再给每一个唯一元素分配一个连续的整数索引来构建的。这种映射是必要的,因为BIT操作需要使用连续的索引范围来有效地更新和查询。如果直接使用元素的原始值作为索引,可能会导致索引过大(尤其是在元素值范围广泛时),从而增加空间复杂度。通过将元素映射到一个较小的、连续的索引范围内,我们可以使空间使用更加高效,并确保BIT的操作能够正确执行。
🦆
题解中的`diff = len(a) - len(b) - tmp`这一行代码的逻辑是如何决定元素应该添加到arr1还是arr2的?
在这行代码中,`diff`计算的是数组`a`和`b`的长度差减去当前元素之后所有元素的数量(即`tmp`,通过BIT计算得到)。`diff`的值用于决定新元素应该添加到哪一个数组中。如果`diff`大于0,或者`diff`等于0且`a`的长度不大于`b`的长度,新元素会被添加到数组`a`中;否则,添加到数组`b`中。这种方法的目的是尽可能平衡两个数组的长度,同时考虑到元素的相对大小顺序,以达到题目的要求。

相关问题