leetcode
leetcode 2451 ~ 2500
对数组执行操作使平方和最大

对数组执行操作使平方和最大

难度:

标签:

题目描述

You are given a 0-indexed integer array nums and a positive integer k.

You can do the following operation on the array any number of times:

  • Choose any two distinct indices i and j and simultaneously update the values of nums[i] to (nums[i] AND nums[j]) and nums[j] to (nums[i] OR nums[j]). Here, OR denotes the bitwise OR operation, and AND denotes the bitwise AND operation.

You have to choose k elements from the final array and calculate the sum of their squares.

Return the maximum sum of squares you can achieve.

Since the answer can be very large, return it modulo 109 + 7.

 

Example 1:

Input: nums = [2,6,5,8], k = 2
Output: 261
Explanation: We can do the following operations on the array:
- Choose i = 0 and j = 3, then change nums[0] to (2 AND 8) = 0 and nums[3] to (2 OR 8) = 10. The resulting array is nums = [0,6,5,10].
- Choose i = 2 and j = 3, then change nums[2] to (5 AND 10) = 0 and nums[3] to (5 OR 10) = 15. The resulting array is nums = [0,6,0,15].
We can choose the elements 15 and 6 from the final array. The sum of squares is 152 + 62 = 261.
It can be shown that this is the maximum value we can get.

Example 2:

Input: nums = [4,5,4,7], k = 3
Output: 90
Explanation: We do not need to apply any operations.
We can choose the elements 7, 5, and 4 with a sum of squares: 72 + 52 + 42 = 90.
It can be shown that this is the maximum value we can get.

 

Constraints:

  • 1 <= k <= nums.length <= 105
  • 1 <= nums[i] <= 109

代码结果

运行时间: 1189 ms, 内存: 29.6 MB


/*
 * Problem: Given an array of integers nums and an integer k, you can perform an operation any number of times to modify the array.
 * You can choose two different indices i and j, then update nums[i] to (nums[i] AND nums[j]) and nums[j] to (nums[i] OR nums[j]).
 * The goal is to maximize the sum of squares of k elements from the final array. Return the result modulo 10^9 + 7.
 */
import java.util.Arrays;

public class Solution {
    public int maxSumOfSquares(int[] nums, int k) {
        // First, sort the array in descending order using Streams
        nums = Arrays.stream(nums).boxed()
                      .sorted((a, b) -> b - a)
                      .mapToInt(i -> i)
                      .toArray();
        // Calculate the sum of squares of the first k elements
        long sum = Arrays.stream(nums)
                         .limit(k)
                         .mapToLong(num -> (long) num * num)
                         .sum();
        // Return the result modulo 10^9 + 7
        return (int) (sum % 1000000007);
    }
}

解释

方法:

该题解首先获取数组中最大数的二进制位长度。然后,创建一个数组 f,其长度为最大二进制位长度,用于统计 nums 中每个比特位上 1 的个数。随后,采用贪心算法尝试构造最大的数。具体来说,从最高位到最低位,如果某个位上有 1,就将该位加到构造的数 x 中,并更新计数。这样构建的 x 将会是局部最大的可能值。重复这一过程 k 次或直到无法构造更多的非零数 x。每次迭代中计算 x 的平方,并累加到结果 ans 中。最终,返回的 ans 就是 k 个数的平方和最大的可能值。

时间复杂度:

O((n+k)*m)

空间复杂度:

O(m)

代码细节讲解

🦆
题解中提到的操作`选择两个互不相同的下标 i 和 j ,同时将 nums[i] 更新为 (nums[i] AND nums[j]) 且将 nums[j] 更新为 (nums[i] OR nums[j])`,这种操作如何保证最终能够形成k个最大的数值?
题解中描述的操作实际上是不会形成 k 个最大数值的确切解决方案。这种操作仅仅是对位操作的一种思考,其目的在于通过组合 nums[i] 和 nums[j] 的位来尝试形成更大的数值。然而,这种操作并不直接关注于形成最大的 k 个数值,而是更多的是通过位操作的方式尝试增加某些数的大小。真正的解决方案是使用贪心算法从数组 f 中构建最大可能的数,这种方法更直接有效地针对问题的目标。
🦆
在提到的贪心算法中,`从最高位到最低位`的构造方式,为什么是从最高位开始,较低位的1的数量是否会影响这种构造方式的有效性?
在构造最大数值的过程中,从最高位到最低位开始是因为高位的数值权重远大于低位。例如,在二进制表示中,最高位(如第 31 位)的权重是 2^31,远大于第 1 位的权重 2^0。因此,为了使得构造的数值尽可能大,应优先考虑在高位放置尽可能多的 1。虽然低位的 1 的数量可能较多,但它们对最终数值的影响较小,因此从最高位开始构造是最有效的策略。
🦆
题解中的数组f用于存储每个位上1的个数,这种方法对于非常大的nums数组是否仍然有效,有没有可能造成计算上的延迟或内存不足?
数组 f 的长度由 nums 中最大数的二进制位数决定,通常为 32 或 64,这取决于数据类型(如 int 或 long)。因此,f 的内存占用是非常小的,即使对于非常大的 nums 数组,f 数组的大小也不会变得很大。此外,对于每个位的计算,虽然需要遍历整个 nums 数组,但这是线性时间复杂度的操作,通常对于现代计算系统来说是可接受的。总的来说,这种方法在空间和时间上都是高效的,适用于处理大规模数据。

相关问题