首页 > 解决方案 > Map 中的PosibleSums 与Java 8 中给定的双精度或双精度数组列表

问题描述

下面的代码给出了给定双数组的所有可能总和,如何对 java8 流执行相同操作并在 `Map<Integer,Double[]> 中产生结果,如下所示

(0,[15],[0.55])

没有地图实现的代码:

public class PossibleDoubleSums {
    public static void getAllSums(double []arr, double startingValue, int pos  ) {
   
        for (int i = pos; i < arr.length; i++) {
            
            double currentValue = startingValue + arr[i];
           System.out.println(currentValue+"");
           
            getAllSums(arr, currentValue, i + 1);
        }
        
    }
     
    public static void main(String[] args) {          
        double arr[] = {15.00, 0.55,25.00, 7.00};
        getAllSums(arr, 0, 0 ); // Test array
    
    }
}

标签: java

解决方案


返回可能的总和

class Solution {
    public static List<Double> solve(double[] arr) {
        return IntStream.range(0, 1 << arr.length).boxed()
            .filter(n -> (n & (n - 1)) != 0)
            .map(n -> IntStream.range(0, arr.length)
                .filter(i -> ((n >> i) & 1) == 1)
                .mapToDouble(i -> arr[i])
                .sum())
            .collect(Collectors.toList());
    }
}

用法

final double[] arr = { 15.00, 0.55, 25.00, 7.00 };
System.out.println(solve(arr));
// Outputs [15.55, 40.0, 25.55, 40.55, 22.0, 7.55, 22.55, 32.0, 47.0, 32.55, 47.55]

返回可能的对

class Solution {
    public static List<Double[]> solve(double[] arr) {
        return IntStream.range(0, 1 << arr.length).boxed()
            .filter(n -> (n & (n - 1)) != 0)
            .map(n -> IntStream.range(0, arr.length).boxed()
                .filter(i -> ((n >> i) & 1) == 1)
                .map(i -> arr[i])
                .toArray(Double[]::new))
            .collect(Collectors.toList());
    }
}

用法

final double[] arr = { 15.00, 0.55, 25.00, 7.00 };
        
final List<Double[]> result = solve(arr);
for (Double[] resultArr : result) {
    System.out.println(Arrays.toString(resultArr));
}

输出

[15.0, 0.55]
[15.0, 25.0]
[0.55, 25.0]
[15.0, 0.55, 25.0]
[15.0, 7.0]
[0.55, 7.0]
[15.0, 0.55, 7.0]
[25.0, 7.0]
[15.0, 25.0, 7.0]
[0.55, 25.0, 7.0]
[15.0, 0.55, 25.0, 7.0]

解释

{15.00, 0.55, 25.00, 7.00}让我们使用作为输入数组来分解它:

  1. IntStream.range(0, 1 << arr.length)创建一个从 0 到 的值流1 << arr.length。表达式1 << n与 相同Math.pow(n, 2),因此1 << arr.length等于 16。

现在的流是IntStream({0, 1, 2, 3, ..., 12, 13, 14, 15}).

  1. boxed()将此转换IntStreamStream<Integer>. 这允许我们最终将其转换为 a List<Integer>

现在的流是Stream<Integer>({0, 1, 2, 3, ..., 12, 13, 14, 15}).

  1. filter(n -> (n & (n - 1)) != 0)从流中删除所有 2 的幂元素,包括 0(说明)。为什么是这样?让我们看一下当前流的二进制表示:

    {0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111}
    

    现在将每个位分配给其各自的数组元素:数字0110对应于元素{0.55, 25.00},数字0001对应于元素{7.00},数字1111对应于所有元素 ( {15.00, 0.55, 25.00, 7.00}),因为所有位都已设置。

    根据您的测试用例,我们不能在输出数组中包含输入数字(例如,输出数组中不应包含 15.0、0.55、25 或 7)。因此,我们不能包含包含单个位的数字(例如00010100)。这些数字是 2 的幂,因此我们必须删除它们。

现在的流是Stream<Integer>({3, 5, 6, 7, ..., 12, 13, 14, 15}).

  1. map(...)将此流的元素映射到另一种类型。对于每个元素n(假设n等于 6),

    1. IntStream.range(0, arr.length)创建一个从 0 到 4 的流。

    现在的子流是IntStream({0, 1, 2, 3}).

    1. filter(i -> ((n >> i) & 1) == 1)仅保留为 1 的位的索引。

    现在的子流是IntStream({1, 2}). 注意n等于 6,其二进制表示为0110。由于设置了中间两位,因此将保留输入数组中的中间两位元素。

    1. mapToDouble(i -> arr[i])将每个位映射到输入数组中的相应元素。

    现在的子流是IntStream({0.55, 25.00}).

    1. sum()对来自该流的所有元素求和。

    结果是25.55

  2. collect(Collectors.toList())将为此流中的所有元素重复第 4 步,返回一个List<Double>.

结果是[15.55, 40.0, 25.55, 40.55, 22.0, 7.55, 22.55, 32.0, 47.0, 32.55, 47.55]


推荐阅读