leetcode
leetcode 2451 ~ 2500
找出数组中的 K-or 值

找出数组中的 K-or 值

难度:

标签:

题目描述

You are given an integer array nums, and an integer k. Let's introduce K-or operation by extending the standard bitwise OR. In K-or, a bit position in the result is set to 1 if at least k numbers in nums have a 1 in that position.

Return the K-or of nums.

 

Example 1:

Input: nums = [7,12,9,8,9,15], k = 4

Output: 9

Explanation:

Represent numbers in binary:

Number Bit 3 Bit 2 Bit 1 Bit 0
7 0 1 1 1
12 1 1 0 0
9 1 0 0 1
8 1 0 0 0
9 1 0 0 1
15 1 1 1 1
Result = 9 1 0 0 1

Bit 0 is set in 7, 9, 9, and 15. Bit 3 is set in 12, 9, 8, 9, and 15.
Only bits 0 and 3 qualify. The result is (1001)2 = 9.

Example 2:

Input: nums = [2,12,1,11,4,5], k = 6

Output: 0

Explanation: No bit appears as 1 in all six array numbers, as required for K-or with k = 6. Thus, the result is 0.

Example 3:

Input: nums = [10,8,5,9,11,6,8], k = 1

Output: 15

Explanation: Since k == 1, the 1-or of the array is equal to the bitwise OR of all its elements. Hence, the answer is 10 OR 8 OR 5 OR 9 OR 11 OR 6 OR 8 = 15.

 

Constraints:

  • 1 <= nums.length <= 50
  • 0 <= nums[i] < 231
  • 1 <= k <= nums.length

代码结果

运行时间: 42 ms, 内存: 16.0 MB


/*
 * 思路:
 * 1. 利用 Java Stream 对数组进行处理。
 * 2. 对于每一位,我们通过 Stream 检查有多少数字的该位为 1。
 * 3. 如果某一位上有至少 k 个 1,则将该位结果置为 1。
 */

import java.util.stream.IntStream;

public class KOrStream {
    public static int findKOrValue(int[] nums, int k) {
        int maxBits = IntStream.of(nums).map(num -> Integer.toBinaryString(num).length()).max().orElse(0);
        int result = 0;
        for (int i = 0; i < maxBits; i++) {
            int bitIndex = i;
            long count = IntStream.of(nums).filter(num -> (num & (1 << bitIndex)) != 0).count();
            if (count >= k) {
                result |= (1 << i);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int[] nums1 = {7, 12, 9, 8, 9, 15};
        int k1 = 4;
        System.out.println(findKOrValue(nums1, k1));  // 输出:9

        int[] nums2 = {2, 12, 1, 11, 4, 5};
        int k2 = 6;
        System.out.println(findKOrValue(nums2, k2));  // 输出:0

        int[] nums3 = {10, 8, 5, 9, 11, 6, 8};
        int k3 = 1;
        System.out.println(findKOrValue(nums3, k3));  // 输出:15
    }
}

解释

方法:

本题解的思路首先是对数组进行排序。排序后,对于每一个位(从0到30位,共31位,因为整数的范围是到2^31),算法尝试找出有多少个数字的该位是1。通过移位操作,算法逐位检查每个数字。算法维护一个指针start,该指针指向第一个大于等于当前位值D的数字。这是因为小于D的数字在该位一定是0。从start开始,算法统计该位为1的数字数量,如果数量达到k,则将此位加入到结果res中。这种方法避免了对于每一位都从头到尾扫描整个数组。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在处理位运算时,需要先对数组进行排序?如何影响算法的效率和结果?
对数组进行排序主要是为了优化位运算过程中的效率。通过排序,可以快速定位到那些在特定位上可能为1的数字,从而避免了对整个数组进行全面扫描。排序后,数组的数值从小到大排列,对于二进制来说,较大的数值在高位上更可能为1。因此,一旦确定了某一位的最小阈值D(1左移位数i得到),可以使用二分查找或线性扫描的方式迅速跳过所有小于D的数,这些数在该位上肯定为0。这种方法减少了无效的检查,提高了算法的整体效率。
🦆
解题思路中提到的指针`start`是如何准确移动到第一个大于等于当前位值D的数字的?能否详细说明其逻辑过程?
指针`start`的移动逻辑是基于数组已经排序的事实。对于每一位i,计算位值D(1左移位数i)。接着算法从当前`start`位置开始扫描数组,直到找到第一个大于等于D的数字。因为数组是有序的,所以小于D的数在该位上必定是0,而大于等于D的数字在该位上可能为1。这样就能够快速定位到可能需要计数的起始位置,从而跳过无关的数值,并减少不必要的比较。这个过程可以视为一种优化的线性扫描,其效率高于从头开始的全扫描。
🦆
在每一位的处理过程中,计数到达k个1后,为什么可以提前终止循环而不继续检查后续的数字?
在每一位的处理中,一旦发现有k个数字的该位都为1,意味着在该位上,已经满足题目条件要求的至少k个1。由于我们的目标是确定哪些位在结果数字中应当为1(即在这些位上至少有k个原数组中的数字对应位为1),找到这k个1后,任何额外的1都不会改变这一位在最终结果中应该为1的事实。因此,一旦这个条件被满足,可以立即将该位加入结果,并终止当前位的进一步检查,这样做可以节省时间,避免不必要的计算。

相关问题