算法之数组和问题
时间:2022-05-04
本文章向大家介绍算法之数组和问题,主要内容包括算法题之数组和求解、扩展、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
算法题之数组和求解
数组和问题
加上给定一个数组和值x。设计一个算法使得如果数组中存在两个元素的和为x,则输出两个元素的值组成的数组(不区分先后),否则输出{-1, -1}。
分析:
- 最简单的办法,就是依次求每个元素与其他元素的和。这个就是经典的握手问题,不难得出其最坏时间复杂度为: (Theta)((n^2)) 这种指数级别的时间复杂度必然不是我们想要的,直接PASS
- 先做排序然后再进行查找: 假设使用前面已知的最快的排序算法,最坏时间复杂度为: (Theta)(nlg(n))。之后可以使用二分查找法对每个针对每个元素查找 x - arr[i] 是否在数组中,此时时间最坏时间复杂度为: (Theta)(nlg(n))。该算法实现的代码如下:
private static int[] findSum(int[] arr, int sum) {
// STEP1: 先对数组采用归并排序进行排序
mergeSort(arr, 0, arr.length);
// STEP2: 遍历数组,用二分查找法查找是否存在sum-arr[i]的元素
for (int i=0; i<arr.length; i++) {
int j = binarySearch(arr, 0, arr.length, sum - arr[i]);
if (j != -1) {
if (j != i) {
return new int[] {arr[i], arr[j]};
} else {
// j = i的时候,则需要判断j的左侧和右侧的值是否和j相等,相等则证明存在两个元素
if (arr[j - 1] == arr[j]) {
return new int[] {arr[i], arr[j - 1]};
} else if (arr[j + 1] == arr[j]) {
return new int[] {arr[i], arr[j + 1]};
}
}
}
}
return new int[]{-1, -1};
}
注意其中的mergeSort和binarySearch调用的是前一章节所指的代码http://www.cnblogs.com/Kidezyq/p/8379267.html。
扩展
- 其实对于求两个元素的和有一种时间复杂度为:(Theta)(n)的算法。该算法利用了桶排序的思想,借助Map的特殊数据结构。我们这里以arr[i]为key,i为value。要判断sum-arr[i]是否存在数组中,只要看map.get(sum-arr[i])是否为空即可。实现的代码如下:
private static int[] findSumWithMap(int[] arr, int sum) {
Map<Integer, Integer> map = new HashMap<>();
// STEP1: 将数据入map
for (int i = 0; i < arr.length; i++) {
map.put(arr[i], i);
}
// STEP2: 开始判断sum-arr[i]是否在map中
for (int i = 0; i < arr.length; i++) {
// 因为遍历顺序同放入map的顺序都是从前到后,所以如果存在多个同值元素,其最终会将后者的下标放入map,此时不影响判断逻辑
if (map.get(sum - arr[i]) != null && i != map.get(sum - arr[i])) {
return new int[]{arr[i], sum - arr[i]};
}
}
return new int[]{-1, -1};
}
- 其实对于上面的分析方法2,还有一个优化的方法,可以对排序后的数组在时间:(Theta)(n)之内找到两个和为指定值的算法。方法的思想还是二分查找法。首先取两个下边lowIndex和upIndex,最开始的时候lowIndex指向数组首元素,upIndex指向数组末尾元素。然后比对arr[lowIndex] + arr[upIndex]与sum的关系。根据比对的结果分别对lowIndex和upIdex进行移动。此时对于后续的整个查找过程只需要(Theta)(n)时间即可。源代码如下:
private static int[] findSumTwoSide(int[] arr, int sum) {
// STEP1: 使用归并排序对数组进行排序
mergeSort(arr, 0, arr.length);
// STEP2: 进行两端查找
int lowIndex = 0;
int upIndex = arr.length - 1;
while (upIndex > lowIndex) {
if (arr[lowIndex] + arr[upIndex] == sum) {
// 相等直接返回
return new int[] {arr[lowIndex], arr[upIndex]};
} else if (arr[lowIndex] + arr[upIndex] < sum) {
// 小于左侧右移
lowIndex++;
} else {
// 大于右侧左移
upIndex--;
}
}
return new int[] {-1, -1};
}
- 该题可以延伸至n个元素的和:
其解决思想就是分治了。将n个元素的规模依次降低,最终降到2个元素的和。这里给出三个元素求和的例子,其他多维依次类推:
private static int[] findSumOf3Digits(int[] arr, int sum) {
// STEP1:先调用归并排序算法进行排序
mergeSort(arr, 0, arr.length);
// STEP2: 进行细化问题处理
// 先申请一个数组来存储排除一个元素后的数组元素组成的新的数组
int[] leftArr = new int[arr.length - 1];
for (int i = 0; i < arr.length; i++) {
// 复制arr[i]左侧元素到数组起始位置
if (i > 0) {
System.arraycopy(arr, 0, leftArr, 0, i);
}
// 复制arr[i]右侧元素到数组结尾位置
if (i < arr.length - 1) {
System.arraycopy(arr, i + 1, leftArr, i, arr.length - i - 1);
}
// 如果剩下两个数的和满足,则返回三个元素
int[] leftIndexes = findSumTwoSide(leftArr, sum - arr[i]);
if (!Arrays.equals(leftIndexes, new int[] {-1, -1})) {
return new int[] {arr[i], leftIndexes[0], leftIndexes[1]};
}
}
return new int[] {-1, -1, -1};
}
- 数据源控件参数类Parameter
- 我们来继续研究 mybatis 框架sql映射文件的属性
- 开源.NET邮件服务器
- 次次获得《头脑王者》满分的秘诀
- 如何在ASP.NET 2.0中定制Expression Builders
- codeproject 几篇asp.net文章
- .NET Web 自动化测试工具
- Javascript数组常用方法[包含MS AJAX.NET的prototype扩展方法]示例
- 10步骤优化SQL Server 数据库性能
- 漫谈语音合成之Char2Wav模型
- [基础]Javascript中的继承示例代码
- javascript天生就具备类似c#中的"委托"功能
- 使用MonoDevelop开发跨平台的应用程序
- Pycharm使用技巧总结
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 用python爬虫,pyinstaller写一个属于自己的彩虹屁生成器!
- 2020牛客寒假算法基础集训营4 C 子段乘积
- Callable and Future in Java(java中的Callable和Future)
- Java类 初步学习
- Gephi可视化拓扑图简单实战
- python连接到SQList数据库以及简单操作
- 在markdown编辑器使用html绘制表格
- 循环不变式:算法中基础概念的明晰
- Codeforces Round #615 (Div. 3)B. Collecting Packages
- 七大设计原则、单一职责原则
- JSP 基本凉凉,学妹不知道他是啥
- Codeforces Round #615 (Div. 3)C. Product of Three Numbers
- Codeforces Round #622 (Div. 2) A.Fast Food Restaurant
- 渗透测试实战 | 一次信息泄露引发的越权
- Vue创建项目及基本语法 一