【算法之美】你可能想不到的归并排序的神奇应用 — leetcode 327. Count of Range Sum
又是一道有意思的题目,Count of Range Sum。(PS:leetcode 我已经做了 190 道,欢迎围观全部题解 https://github.com/hanzichi/leetcode)
题意非常简单,给一个数组,如果该数组的一个子数组,元素之和大于等于给定的一个参数值(lower),小于等于一个给定的参数值(upper),那么这为一组解,求总共有几组解。
一个非常容易想到的解法是两层 for 循环遍历子数组首尾,加起来判断,时间复杂度 O(n^2)。
/**
* @param {number[]} nums
* @param {number} lower
* @param {number} upper
* @return {number}
*/
var countRangeSum = function(nums, lower, upper) {
var len = nums.length;
var ans = 0;
for (var i = 0; i < len; i++) {
var sum = 0;
for (var j = i; j < len; j++) {
sum += nums[j];
if (sum >= lower && sum <= upper)
ans++;
}
}
return ans;
};
交了下 TLE 了,看了下测试数据,数组长度为 9000,复杂度达到了 8100w,还是蛮大的。其实题目中也说了: A naive algorithm of O(n2) is trivial. You MUST do better than that.
如何将复杂度降到 log 级别?想到了二分的方法。可以将子数组和转换成两个前缀数组和的差,定义数组 sum, sum[i] 表示数组前 i 个元素的和,特殊的, sum[0]=0,那么元素 i 到元素 j 的和可以表示为 sum[j]-sum[i-1]。我们枚举 0 到 nums.length,比如枚举到了 sum[j],我们需要求满足条件的 i(i<j),sum[j]-sum[i] 的值满足大于等于 lower,小于等于 upper。我们需要枚举 sum[0] 到 sum[i],复杂度还是 O(n^2),如果 sum[0] 到 sum[i] 有序呢?
解法似乎呼之而出,用二分维护有序数组(用 splice 插入),同时用二分找到临界的数据,一次迭代需要多次二分。二分查找相关可以看我以前的文章 二分查找大集合(妈妈再也不用担心我的二分查找了)。
注意下二分的边界,代码很容易写出来。
function binarySearch1(a, target) {
target += 1;
var start = 0
, end = a.length - 1;
while(start <= end) {
var mid = ~~((start + end) >> 1);
if (a[mid] >= target)
end = mid - 1;
else
start = mid + 1;
}
return start;
}
function binarySearch2(a, target) {
var start = 0
, end = a.length - 1;
while(start <= end) {
var mid = ~~((start + end) >> 1);
if (a[mid] >= target)
end = mid - 1;
else
start = mid + 1;
}
return end;
}
var countRangeSum = function(nums, lower, upper) {
var len = nums.length;
var sum = [];
var ans = 0;
var num = 0;
sum.push(0);
for (var i = 0; i < len; i++) {
ans += nums[i];
var a = ans - upper;
var b = ans - lower;
var pos1 = binarySearch2(sum, a) + 1;
var pos2 = binarySearch1(sum, b) - 1;
num += pos2 - pos1 + 1;
var pos3 = binarySearch1(sum, ans);
sum.splice(pos3, 0, ans);
}
return num;
};
很不幸,还是 TLE 了,究其原因,我觉得应该是调用了 n 次 splice 方法。 感觉维护一棵二叉搜索树应该是可行的,无奈不会手写二叉搜索树 = =
那么可行的解法是什么呢?答案是归并排序的 "另类使用"。这里不讲归并排序,关于归并排序,可见我以前的文章 http://www.cnblogs.com/zichi/p/4796727.html。
言归正传,首先预处理数组的前缀和,保存到数组 sum 中。然后用归并排序对数组 sum 进行排序,归并排序中有一步调用 merge 函数,将有序的左数组和右数组进行合并,而这时的右数组中的任一元素在 sum 数组中的位置正是在左数组任一元素之后!利用这,我们可以在 merge 前,对 left 数组和 right 数组满足条件的元素进行求解。
这个函数我定义为 getAns:
// 返回 b[j] - a[i] 值在 [wlower, wupper] 范围内组数
function getAns(a, b) {
var sum = 0;
var lena = a.length;
var lenb = b.length;
var start = 0;
var end = 0;
for (var i = 0; i < lenb; i++) {
// to get start
while (b[i] - a[start] >= wlower) {
start++;
}
// to get end
while (b[i] - a[end] > wupper) {
end++;
}
sum += start - end;
}
return sum;
}
做完一次归并排序,每次 left 和 right 数组合并前进行判断,就将所有 sum[j]-sum[i](j>i) 的情况进行了判断,简直神奇!
完整代码参考我的 Github https://github.com/hanzichi/leetcode/blob/master/Algorithms/Count%20of%20Range%20Sum/count-of-range-sum.js
224ms!Your runtime beats 100.00% of javascriptsubmissions 还是有点小激动
【算法之美】你可能想不到的归并排序的神奇应用 — leetcode 327. Count of Range Sum的更多相关文章
- 【算法之美】求解两个有序数组的中位数 — leetcode 4. Median of Two Sorted Arrays
一道非常经典的题目,Median of Two Sorted Arrays.(PS:leetcode 我已经做了 190 道,欢迎围观全部题解 https://github.com/hanzichi/ ...
- JavaScript 数据结构与算法之美 - 归并排序、快速排序、希尔排序、堆排序
1. 前言 算法为王. 想学好前端,先练好内功,只有内功深厚者,前端之路才会走得更远. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScript ,旨在入门数据结构与算 ...
- JavaScript 数据结构与算法之美 - 线性表(数组、栈、队列、链表)
前言 基础知识就像是一座大楼的地基,它决定了我们的技术高度. 我们应该多掌握一些可移值的技术或者再过十几年应该都不会过时的技术,数据结构与算法就是其中之一. 栈.队列.链表.堆 是数据结构与算法中的基 ...
- JavaScript 数据结构与算法之美 - 十大经典排序算法汇总(图文并茂)
1. 前言 算法为王. 想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手:只有内功深厚者,前端之路才会走得更远. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 ...
- JavaScript 数据结构与算法之美 - 冒泡排序、插入排序、选择排序
1. 前言 算法为王. 想学好前端,先练好内功,只有内功深厚者,前端之路才会走得更远. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScript ,旨在入门数据结构与算 ...
- 《数据结构与算法之美》 <05>链表(下):如何轻松写出正确的链表代码?
想要写好链表代码并不是容易的事儿,尤其是那些复杂的链表操作,比如链表反转.有序链表合并等,写的时候非常容易出错.从我上百场面试的经验来看,能把“链表反转”这几行代码写对的人不足 10%. 为什么链表代 ...
- 《数据结构与算法之美》 <01>复杂度分析(上):如何分析、统计算法的执行效率和资源消耗?
我们都知道,数据结构和算法本身解决的是“快”和“省”的问题,即如何让代码运行得更快,如何让代码更省存储空间.所以,执行效率是算法一个非常重要的考量指标. 那如何来衡量你编写的算法代码的执行效率呢?这里 ...
- 如何用快排思想在O(n)内查找第K大元素--极客时间王争《数据结构和算法之美》
前言 半年前在极客时间订阅了王争的<数据结构和算法之美>,现在决定认真去看看.看到如何用快排思想在O(n)内查找第K大元素这一章节时发现王争对归并和快排的理解非常透彻,讲得也非常好,所以想 ...
- 【EatBook】-NO.2.EatBook.2.JavaArchitecture.1.001-《修炼Java开发技术在架构中体验设计模式和算法之美》-
1.0.0 Summary Tittle:[EatBook]-NO.2.EatBook.2.JavaArchitecture.1.001-<修炼Java开发技术在架构中体验设计模式和算法之美&g ...
随机推荐
- Asp.net MVC Razor模板引擎技巧分享
Razor是Asp.net MVC中新的默认模板类型, 语法简单易用.这篇文章不涉及Razor的语法,主要介绍Razor的一些在MVC项目中的使用技巧,以及脱离MVC环境下,如何使用Razor. 阅读 ...
- 如何恢复Mysql数据库
这里说的MySql恢复数据库,是指没有通过正常备份的情况下,通过Mysql保存的数据文件如何恢复数据库. 由于在一台测试机器上打算重新安装Mysql数据库,由于简单粗暴的直接卸载了,没有备份公司Dis ...
- ERROR [org.apache.hadoop.security.UserGroupInformation] - PriviledgedActionExcep
换了个环境,出现此异常 016-10-18 23:54:01,334 WARN [org.apache.hadoop.util.NativeCodeLoader] - Unable to load n ...
- Sql Server之旅——第十一站 简单说说sqlserver的执行计划
我们知道sql在底层的执行给我们上层人员开了一个窗口,那就是执行计划,有了执行计划之后,我们就清楚了那些烂sql是怎么执行的,这样 就可以方便的找到sql的缺陷和优化点. 一:执行计划生成过程 说到执 ...
- mysql字符编码集(乱码)问题解决
1.创建数据库 CREATE DATABASE `test` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'; 创建表 CREATE TABLE tp_w ...
- Android之drawable state各个属性详解
android:drawable 放一个drawable资源android:state_pressed 是否按下,如一个按钮触摸或者点击.android:state_focused 是否取得焦点,比如 ...
- Linux dd
一.简介 二.实例 1)复制二进制文件指定章节 iflag=skip_bytes bs= count= of=test 2)修改二进制文件指定章节 oflag=seek_bytes bs= count ...
- 《Invert》开发日志03:一些想法
本来标题想写“详细设计”,但是由于独立游戏开发有很强的探索性,最终项目一定是经过原型调整迭代而来的,所以在实际效果出来之前把设计做得太细并没有太大意义,现在只能先陈列目前的一些想法,不能定义“它是什么 ...
- AC日记——ISBN号码 openjudge 1.7 29
29:ISBN号码 总时间限制: 1000ms 内存限制: 65536kB 描述 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字.1位识别码和3位分隔符,其规定格式如“x ...
- Visio连接数据表实体外键[快捷记录]
打开数据库模型图. 单击“常用”工具栏上的“连接线”工具. 将“连接线”工具放在父表的中心上,使表的四周出现轮廓线,然后拖到子表的中心.当子表出现轮廓线时,松开鼠标按钮. 两个连接点均变为红色,同时父 ...