【算法之美】你可能想不到的归并排序的神奇应用 — 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 ...
随机推荐
- 集合1--毕向东java基础教程视频学习笔记
Day14 集合框架01 体系概述02 共性方法03 迭代器04 List集合共性方法05 ListIterator06 List集合具体对象特点07 Vector中的枚举 01 体系概述 集合类为什 ...
- java中的list,set,数组之间的转换
使用该工具类import org.apache.commons.collections.CollectionUtils; 在Apache Jakarta Commons Collections中 St ...
- 第二题 已知有十六支男子足球队参加2008 北京奥运会。写一个程序,把这16 支球队随机分为4 个组。采用List集合和随机数 2008 北京奥运会男足参赛国家: 科特迪瓦,阿根廷,澳大利亚,塞尔维亚,荷兰,尼日利亚、日本,美国,中国,新西 兰,巴西,比利时,韩国,喀麦隆,洪都拉斯,意大利
package com.hanqi.test; import java.util.ArrayList; import java.util.List; import java.util.Random; ...
- windows环境下无法引用全局安装的模块问题
问题 在node项目中,往往需要安装一些依赖的包,通常我们采取全局安装的方式,来减少一些包重复安装带来的烦恼. 但是全局安装后出现无法使用的情况,可能是你NODE_PATH没有设置或者不正确造成的. ...
- get_free_page
/** 0.11用了 unsigned char */static unsigned short mem_map [ PAGING_PAGES ] = {0,}; /* * Get physical ...
- C++学习笔记【转载】
转载自:http://www.cnblogs.com/maowang1991/p/3290321.html 1.struct成员默认访问方式是public,而 class默认访问方式是private! ...
- Linux 下从头再走 GTK+-3.0 (四)
实际的应用中,往往有很多个控件, 同样GTK提供了很多种布局方案,Box, Fixed , Table , Grid 等. 接下来试试网格布局 Grid. 我们创建 example4.c ,内容如下: ...
- 工欲善其事必先利其器——dreamweaver
1.内置了一个webkit内核,所以实时视图与chrome浏览器效果一样. 2.DW中主浏览器的快捷键是f12,所以可以f12快速打开浏览器. 3.DW中首选项无法恢复到默认值. 4.有用首选项 5. ...
- POJ 1696 Space Ant 【极角排序】
题意:平面上有n个点,一只蚂蚁从最左下角的点出发,只能往逆时针方向走,走过的路线不能交叉,问最多能经过多少个点. 思路:每次都尽量往最外边走,每选取一个点后对剩余的点进行极角排序.(n个点必定能走完, ...
- Unity Ragdoll(布娃娃系统)
逼真的动作如何实现的? 在一些游戏中当NPC或玩家死亡的时候,死亡的肢体动作十分逼真,这一物理现象如何用Unity来实现呢?Unity物理引擎中的Ragdoll系统,可以用来创建这种效果,具体请参阅以 ...