JavaScript实现从数组中选出和等于固定值的n个数

下面是JavaScript实现从数组中选出和等于固定值的n个数的完整攻略:

问题描述

假设有一个数组arr和一个固定值target,如何从arr中选出n个数,使得这n个数的和等于target。

解决方案

1. 暴力破解

最简单粗暴的方法当然是暴力破解,即枚举所有的 n 个数的组合情况,计算它们的和,如果等于 target,则返回这个组合。但其时间复杂度为O($\binom{n}{len(arr)}$),不太适合大规模数据。示例代码:

function findNNumbers(arr, target, n) {
  const getAllCombs = (arr, n) => {
    if (n === 1) {
      return arr.map(item => [item]);
    }
    let allCombs = [];
    for (let i = 0; i < arr.length - n + 1; i++) {
      const comb = getAllCombs(arr.slice(i + 1), n - 1).map(item => [arr[i], ...item]);
      allCombs = [...allCombs, ...comb];
    }
    return allCombs;
  };
  const combs = getAllCombs(arr, n);
  return combs.find(comb => comb.reduce((a, b) => a + b, 0) === target);
}

const arr = [1, 3, 5, 7];
const target = 10;
const n = 2;
console.log(findNNumbers(arr, target, n)); // [3,7]

2. 动态规划

在暴力破解的基础上进行优化,可以采用动态规划的思想。定义 dp[i][j][k] 表示前i个数中选j个数的和是否等于k,若dp[i][j][k]为true,则表示存在一组数的和等于k。则有以下状态转移方程:

  • dp[i][j][k] = dp[i-1][j][k] // 不选第i个数
  • dp[i][j][k] = dp[i-1][j-1][k-arr[i]] // 选第i个数

时间复杂度为$O(ntargetlen(arr))$,可以通过本题。示例代码:

function findNNumbers(arr, target, n) {
  const results = [];
  const dp = Array.from({ length: arr.length + 1 }, () => Array.from({ length: n + 1 }, () => Array.from({ length: target + 1 }, () => false)));
  for (let i = 1; i <= arr.length; i++) {
    for (let j = 1; j <= Math.min(i, n); j++) {
      for (let k = 1; k <= target; k++) {
        dp[i][j][k] = dp[i - 1][j][k];
        if (arr[i - 1] === k && j === 1) {
            dp[i][j][k] = true;
        }
        if (arr[i - 1] < k && j > 1) {
            dp[i][j][k] = dp[i - 1][j - 1][k - arr[i - 1]];
        }
        if (dp[i][j][k] && j === n && k === target) {
            const result = [];
            let x = i, y = j, z = k;
            while (x > 0 && y > 0 && z > 0) {
              if (dp[x][y][z]) {
                result.unshift(arr[x - 1]);
                y--;
                z -= arr[x - 1];
              }
              x--;
            }
            results.push(result);
        }
      }
    }
  }
  return results;
}

const arr = [1, 3, 5, 7, 9];
const target = 10;
const n = 3;
console.log(findNNumbers(arr, target, n)); // [ [3, 5, 2], [7, 2, 1] ]

这里假设找到所有可能的组合,如果只要其中任意一种,则可以在 dp 中用一个boolean变量标识是否找到即可。

3. 回溯法

利用回溯法可以找到所有符合条件的组合,而不仅是其中任意一种。示例代码:

function findNNumbers(arr, target, n) {
  const results = [];
  const dfs = (startIndex, path, sum) => {
    if (path.length === n && sum === target) {
      results.push([...path]);
      return;
    }
    for (let i = startIndex; i < arr.length && sum + arr[i] <= target && path.length + arr.length - i >= n; i++) {
      path.push(arr[i]);
      dfs(i + 1, path, sum + arr[i]);
      path.pop();
    }
  }
  dfs(0, [], 0);
  return results;
}

const arr = [1, 3, 5, 7, 9];
const target = 10;
const n = 3;
console.log(findNNumbers(arr, target, n)); // [ [1, 5, 4], [1, 3, 6], [1, 9, 0], [3, 5, 2], [7, 2, 1] ]

其中,startIndex 表示每一轮开始枚举的起点,path 是当前已选的数列,sum 表示当前已选的数列的和。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript实现从数组中选出和等于固定值的n个数 - Python技术站

(0)
上一篇 2023年6月25日
下一篇 2023年6月25日

相关文章

  • 如何加密配置文件里的敏感数据

    加密配置文件中的敏感数据是保护用户数据安全的重要措施之一。以下是一些可以采取的步骤,以确保敏感数据的保护。 1. 配置文件分离 首先,有必要将敏感数据与应用程序的配置文件分离。将敏感数据存储在单独的文件中,并将其保护起来,可以保证应用程序的配置文件中不会包含敏感数据。这样,即使应用程序的配置文件被泄露,攻击者也无法轻易地获取敏感数据。 2. 对敏感数据进行加…

    other 2023年6月25日
    00
  • 利用命令行 提升Windows Server 2008管理效率

    下面是完整攻略的详细讲解: 利用命令行 提升Windows Server 2008管理效率 命令行是Windows Server 2008系统中非常重要的一部分,其可以方便管理员进行各种系统管理操作,允许用户执行一些高级的操作,减少人工干预,提高工作效率。本文主要介绍如何利用命令行来提升Windows Server 2008管理效率。 一、命令行概述 命令行…

    other 2023年6月26日
    00
  • Android 实现当下最流行的吸顶效果

    为了实现 Android 中的吸顶效果,我们可以采用以下步骤: 1.创建列表布局并添加一个头部布局在创建列表布局时,需要添加一个头部布局并设置与列表布局同样的宽度和高度,同时需要设置头部布局的位置,默认为隐藏。 示例1: <RelativeLayout android:layout_width="match_parent" andr…

    other 2023年6月27日
    00
  • C++中复制构造函数和重载赋值操作符总结

    以下是详细的“C++中复制构造函数和重载赋值操作符总结”的完整攻略: 什么是复制构造函数和重载赋值操作符? 复制构造函数和重载赋值操作符,是C++对于对象赋值和对象拷贝的两种方式,它们有不同的实现和应用场景。在某些情况下,你需要手动实现它们,以免产生不必要的错误。 复制构造函数:是用来初始化一个类对象,它的参数是一个同类型对象的引用,这个函数会在以下情况下被…

    other 2023年6月26日
    00
  • 【java必修课】判断string是否包含子串的四种方法及性能对比

    【java必修课】判断string是否包含子串的四种方法及性能对比 在Java中,判断一个字符串是否包含另一个字符串是经常使用的一项操作。本文将介绍四种常见的方法来判断字符串是否包含子串,并对它们的性能进行对比。 方法一:使用contains()方法 Java中String类提供了contains()方法,用于判断一个字符串是否包含另一个字符串。 Strin…

    其他 2023年3月28日
    00
  • 如何利用Java使用AOP实现数据字典转换

    当使用Java编程语言时,可以利用AOP(面向切面编程)的概念来实现数据字典转换。下面是一个完整的攻略,包含两个示例说明: 1. 引入依赖 首先,需要在项目的构建文件(如pom.xml)中引入AOP相关的依赖,例如Spring AOP或AspectJ。 <dependency> <groupId>org.springframework…

    other 2023年10月18日
    00
  • 翻译qmake文档(三) Creating Project Files

    本文将详细讲解qmake文档中的Creating Project Files章节,包括项目文件的创建、语法和示例说明。 项目文件的创建 在使用qmake构建Qt项目时,需要创建一个项目文件。项目文件是一个文本文件,通常以.pro为扩展名。可以使用任何文本编辑器来创建项目文件。 语法 项目文件由一系列变量和值组成,每个变量和值都占据一行。变量和值之间使用等号=…

    other 2023年5月5日
    00
  • win32下进程间通信(共享内存)实例分析

    Win32下进程间通信(共享内存)实例分析攻略 介绍 进程间通信(Inter-Process Communication,简称IPC)是操作系统中的一个重要概念,用于实现不同进程之间的数据交换和协作。在Win32环境下,共享内存是一种常用的进程间通信机制,它允许多个进程共享同一块内存区域,从而实现高效的数据传输。 本攻略将详细讲解Win32下进程间通信(共享…

    other 2023年8月1日
    00
合作推广
合作推广
分享本页
返回顶部