以下是近期遇到的三个计(算)算(法)题... 提到这些问题的时候简单理了下思路,后面又以JavaScript代码实现并顺便记个笔记...

至于是什么场景下遇到这些题的么... :)

问题一:从无序数组里取出M个值,总和为N,得出一个解即可
给出思路:
  1. 递归直到长度为M为止,得出数组子集;
  2. 对得出的数组子集进行计算,如果相加的和等于N(如果设置容差T,则相加的和与N的差距小于容差T),则将子集数据存入combArr;
    2.1. 默认只取第一个值,取到后跳出循环;
    2.2. 如果设置取所有结果,则继续循环求之后的子集。
代码如下:
const arr = [14, 30, 38, 15, 34, 20, 10, 5, 35, 32, 27, 11, 9, 50, 21, 29, 3, 47, 26, 39, 18, 17, 40, 37, 49, 23, 22, 43, 33, 1, 24, 8, 16, 12, 25, 28, 48, 2, 41, 44, 45, 46, 4, 13, 42, 36, 31, 19, 6, 7];
// 参数 数组 数量 总和 容差 是否取全部结果
function getCombination(array, count, sum, tolerance, allResult) { const combArr = [];
const $tolerance = isNaN(tolerance) ? 0 : tolerance; if (!count || isNaN(count)) {;
return combArr.push([]), combArr;
} // 是否取所有结果
let getAllResult = false; const generateIdxComb = ($originArray, $count, $array) => {
if ($count === 0) {
const $sum = $originArray.reduce((a, b) => a + b);
if (Math.abs(sum - $sum) <= $tolerance) {
combArr.push($originArray);
if (allResult) {
getAllResult = true;
}
}
return;
}
for (let i = 0, len = $array.length; i <= len - $count; i++) {
if (combArr.length && !getAllResult) {
break;
}
generateIdxComb($originArray.concat($array[i]), $count - 1, $array.slice(i + 1));
}
} // 递归取子集
(generateIdxComb)([], count, array);
return combArr;
}
getCombination(arr, 3, 21);
// output [[14, 5, 2]]
getCombination(arr, 3, 21, 0, true);
// output [[14, 5, 2],[14, 3, 4],...] 27个组合
问题一的扩展,背包问题:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高
在上面的代码做判断条件的修改:
const arr = '[{weight: 1,price: 15}, {weight: 3,price: 12}, {weight: 5,price: 16}, {weight: 6,price: 9}, {weight: 7,price: 18}, {weight: 9,price: 11}]';
// 数组 数量 限定值
function getMaxComb(array, count, sum) {
let combArr = [];
let totalPrice = 0; if (!count || isNaN(count)) {;
return combArr;
} const generateIdxComb = ($originArray, $count, $array) => {
if ($count === 0) {
const $sumWeight = $originArray.reduce((a, b) => a + b.weight, 0);
if ($sumWeight <= sum) {
const $totalPrice = $originArray.reduce((a, b) => a + b.price, 0);
if ($totalPrice > totalPrice) {
totalPrice = $totalPrice;
combArr = $originArray;
}
};
return;
}
for (let i = 0, len = $array.length; i <= len - $count; i++) {
generateIdxComb($originArray.concat($array[i]), $count - 1, $array.slice(i + 1));
}
} // 递归取子集
(generateIdxComb)([], count, array); return combArr;
}
getMaxComb(arr, 3, 17);
// output [{"weight":1,"price":15},{"weight":5,"price":16},{"weight":7,"price":18}]
问题二:取一串字符串里的最长回文
关于这个问题,理了2种思路,一种是空间换时间的,但是在浏览器跑1W以上长度的字符串就导致浏览器奔溃;下面代码中的是另外一种,在浏览器跑了个10000长度字符串的时间为200ms不到。两种方法在nodejs端皆可用,前者效率是后者的10倍左右,所以...就直接贴了效率较佳的代码。
先给出思路:
  1. 考虑到回文长度奇偶的区别,预先处理字符串,中间加_连接;
  2. 以字符串做循环,分别以当前索引的字符为中心将两边的值做比较,如果是回文,则返回回文长度的1/2;
  3. 如果回文长度大于当前存的最长回文长度变量的值,则更新最长回文长度变量和最长回文中心索引值变量;
  4. 当字符串长度减去循环中心小于最长回文长度变量,则说明以右边字符为中心的回文不会比当前获得的最长回文长了,就不用继续浪费计算资源了。
代码如下:
function getLongestPalindrome($value) {

    // 考虑到回文长度是偶数的情况
value = $value.split('').join('_');
// 存最长回文长度 (其实是长度的1/2;从doCkeck中可以看出,返回的仅是循环的值)
let longestPalindromeLen = 0;
// 存最长回文的中心索引值
let palindromeCenter = 0;
// 数组长度
const len = value.length; // 回文检测
function doCheck(idx, value) {
let i = 0;
for (; i <= idx; i++) {
if (value[idx - i] !== value[idx + i]) {
break;
}
}
// 注意这里返回的是 i - 1,所以其实取到的是回文长度的1/2
return i - 1;
} // 遍历数组
for (let i = 0; i < len; i++) {
// 省掉后续的一些判断,因为这时候以右边字符为中心的回文长度已经小于等于最长回文了
if (len - i < longestPalindromeLen) {
break;
}
const checkResult = doCheck(i, value);
if (checkResult && checkResult > longestPalindromeLen) {
longestPalindromeLen = checkResult;
palindromeCenter = i;
}
} // 组成结果
let str = value.slice(palindromeCenter - longestPalindromeLen, palindromeCenter + longestPalindromeLen + 1).replace(/_/g, ''); return str;
} getLongestPalindrome('aba');
// output 'aba'
getLongestPalindrome('adaceebdsdbeecabd');
// output 'aceebdsdbeeca'
getLongestPalindrome('abbac');
// output 'abba'
getLongestPalindrome('12345678765432');
// output '2345678765432'
问题三:下面矩阵中,从1到10的路径中取路径值相加最大的路径
1  -  30 - 15 - 34 - 23
| | | | |
20 - 6 - 8 - 27 - 19
| | | | |
35 - 11 - 9 - 21 - 7
| | | | |
29 - 3 - 50 - 18 - 10
先给出思路:
  1. 分别从"右"和"下"出发,判断两个方向的较大值,作为到路径节点为止的最大值,这样便能够得到最大的路径的值。如下"1-30-6"和"1-20-6",37 > 27,则该节点值为37,以此类推,得出:
1  -  31 - 46  - 80  - 103
| | | | |
21 - 37 - 54 - 107 - 126
| | | | |
56 - 67 - 76 - 128 - 135
| | | | |
85 - 88 - 138 - 156 - 166

  2. 基于以上结果计算并且输出最优路径。上面得到了最大的值为"166",根据"166"开始反推:

156 > 135, 得出 右
138 > 128, 得出 右
88 > 76, 得出 右
85 > 67, 得出 右
85之后只能向上反推,得出3个下
给出结果: 下下下右右右右
代码如下:
const arr = [
[1, 30, 15, 34, 23],
[20, 6, 8, 27, 19],
[35, 11, 9, 21, 7],
[29, 3, 50, 18, 10]
]; function calcPath(matrix) { // 存相加的值用
const bestPathSum = [];
for (let i = 0; i < matrix.length; i++) {
bestPathSum.push([]);
} // 求路径过程,如 1-2-3 3个数当中只有2个"-",可得路径过程 = 路径长度 - 1
let bestPathValue = [];
const RIGHT = '右';
const DOWN = '下';
let goDownLen = matrix.length - 1;
let goRightLen = matrix[0].length - 1; // 二维数组计算,取最大值作为存储
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
// 第一步设置第一个值作为基础
if (i === 0 && j === 0) {
bestPathSum[i][j] = matrix[i][j];
} else if (i === 0) {
// 第一个数组往右计算
bestPathSum[i][j] = bestPathSum[i][j - 1] + matrix[i][j];
} else if (j === 0) {
// 多个数组以第一个值往下计算
bestPathSum[i][j] = bestPathSum[i - 1][j] + matrix[i][j];
} else {
// 除索引 0 外的其他值计算
bestPathSum[i][j] = Math.max(bestPathSum[i - 1][j], bestPathSum[i][j - 1]) + matrix[i][j];
}
}
} // 输出路径
for (let i = goDownLen + goRightLen; i > 0; i--) {
if (goDownLen === 0) {
goRightLen--;
bestPathValue.push(RIGHT);
} else if (goRightLen === 0) {
goDownLen--;
bestPathValue.push(DOWN);
} else {
if (bestPathSum[goDownLen][goRightLen - 1] > bestPathSum[goDownLen - 1][goRightLen]) {
goRightLen--;
bestPathValue.push(RIGHT);
} else {
goDownLen--;
bestPathValue.push(DOWN);
}
}
} const result = {
bestPath: bestPathValue.reverse().join('-'),
maxValue: bestPathSum[bestPathSum.length - 1][bestPathSum[0].length - 1]
} return result;
}
calcPath(arr);
// output {bestPath: "下-下-下-右-右-右-右", maxValue: 166}
至于上面的时间复杂度和空间复杂度结果计算,由于这块知识还不是很稳(还在学习中...),就先不给出计算结果了...再理解理解复杂度计算过程再说...先以运行结果给出结论。
2018年刷完部分网络基础知识,整理出了18篇阅读时的笔记,其中一些例子的计算过程是通过新建场景来计算得出,确保理解的正确,有兴趣的同学可以往前翻一翻随笔。
最后顺便定个2019年小目标:主学JavaScript编程(前端切图仔的身份不能忘),辅补算法知识。
 
 

近期遇到的计(算)算(法)题及解(JavaScript)的更多相关文章

  1. SQLServer 常见SQL笔试题之语句操作题详解

    SqlServer 常见SQL笔试题之语句操作题详解 by:授客 QQ:1033553122 测试数据库 CREATE DATABASE handWriting ON PRIMARY ( name = ...

  2. 牛客网 Java 工程师能力评估 20 题 - 详解

    牛客网 Java 工程师能力评估 20 题 - 详解 不知在看博客的你是否知道 牛客网,不知道就太落后了,分享给你 : 牛客网 此 20 题,绝对不只是 20 题! 免责声明:本博客为学习笔记,如有侵 ...

  3. 关于SQL的几道小题详解

    关于SQL的几道小题详解 当我们拿到题目的时候,并不是急于作答,那样会得不偿失的,而是分析思路,采用什么方法,达到什么目的,还要思考有没有简单的方法或者通用的方法等等,这样才会达到以一当十的效果,这样 ...

  4. Leetcode之回溯法专题-37. 解数独(Sudoku Solver)

    Leetcode之回溯法专题-37. 解数独(Sudoku Solver) 编写一个程序,通过已填充的空格来解决数独问题. 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次.数字 1 ...

  5. 一题多解,ASP.NET Core应用启动初始化的N种方案[上篇]

    ASP.NET Core应用本质上就是一个由中间件构成的管道,承载系统将应用承载于一个托管进程中运行起来,其核心任务就是将这个管道构建起来.在ASP.NET Core的发展历史上先后出现了三种应用承载 ...

  6. 一题多解,ASP.NET Core应用启动初始化的N种方案[下篇]

    [接上篇]"天下大势,分久必合,合久必分",ASP.NET应用通过GenericWebHostService这个承载服务被整合到基于IHostBuilder/IHost的服务承载系 ...

  7. 最短路径Dijkstar算法和Floyd算法详解(c语言版)

    博客转载自:https://blog.csdn.net/crescent__moon/article/details/16986765 先说说Dijkstra吧,这种算法只能求单源最短路径,那么什么是 ...

  8. 【托业】【全真题库】TEST2-语法题

    105 to do sth 不定时可充当形容词修饰名词 In an effort to reduce prices----为降低价格 106. 修饰比较级:far,much,even,still,a ...

  9. 【托业】【全真题库】TEST1-语法题

    TEST01 103. delivery date 交货日期 delivery n.传送,投递; [法](正式)交付; 分娩; 讲演; 104. net revenue 净收入,纯收入 105. re ...

随机推荐

  1. 关于python-flask中规范创建项目的几个关键py项目文件

    1.config.py——配置文件 DEBUG = True DIALECT = 'mysql' DRIVER = 'mysqldb' USERNAME = 'root' PASSWORD = '' ...

  2. 前端ajax技术之跨域问题解决

    这里我使用jquery框架的ajax技术 <script type="text/javascript" src="Assets/js/jquery.min.js&q ...

  3. windows环境下wamp安装redis拓展

    环境: wamp集成环境 安装分为两部 1.安装redis客户端   https://github.com/ServiceStack/redis-windows/raw/master/download ...

  4. Windows 自动化补丁管理

    Windows 自动化补丁管理 Desktop Central,这一倍受欢迎的补丁管理软件旨在修补可能导致安全薄弱.破坏关键系统数据或导致系统不可用的漏洞.管理此类软件漏洞对网络管理员来说简直是噩梦. ...

  5. 0.计划用libgdx写一个六边形回合制slg兵棋游戏

    题主层是一个e社游戏迷,但是因为国家政策,e社已经放弃了中国市场,所以决定自己来做,暂时当一个副业 大致计划: 1,先完成一个类似将军的荣耀的战旗游戏 2.再在其基础上制作一个钢铁雄心或世2 3.然后 ...

  6. 编写shell脚本kill掉占用cpu超过90%以上的程序

    由于集群用户经常会不懂如何提交作业,将作业直接运行到登录节点上,这样导致登录节点的cpu及内存占用很大,导致其他用户甚至无法登录.所以就想到了一种解决方法,写一个shell脚本,常驻登录节点,监控cp ...

  7. JavaScriptDOM

    DOM简介 1.HTML DOM:网页被加载时,浏览器会创建文档对象模型 2.DOM操作HTML:改变HTML的元素.属性.CSS样式.对所有事件作出反应 DOM操作HTML 1.改变HTML输出流 ...

  8. CSS伪类的理解

    因为之前一直对css伪类没有过多的了解,在网上看到一段css代码,不能理解 a:hover span.title{ color:red; ......... } 现通过查询css手册,其实css伪类只 ...

  9. eclipse设置新建jsp文件默认字符编码为utf-8

    在使用Eclipse开发中,编码默认是ISO-8859-1,不支持中文.这样我们每次新建文件都要手动修改编码,非常麻烦.其实我们可以设置文件默认编码,今后再新建文件时就不用修改编码了. 1.打开Ecl ...

  10. java持有对象-集合类

    面阿里的时候,面试就让我说一下集合 当时由于条件原因没听清面试官的问题,后来面试后,面试官让问他问题的时候,才说明白是什么 下面就接受一下我了解的集合类 集合类中大致可以分为两个体系 一.collec ...