算法基础之数组
一、数组定义
数组是一种线性数据结构,每一个元素至多只有一个前驱和一个一个后继。说到线性数据结构除了数组还有链表、栈、队列
。既然有线性数据结构与之相反也有非线性结构,常见的非线形结构有树、图
。在创建数组的时候会为数组分配一块连续的内存空间用于存储数组中的元素。
二、在数组上操作时间复杂度分析
- 在数组上的随机访问的时间复杂度分析,由于数组的元素是存储在一块连续内存空间上。那么对于数组中的任意元素只要知道的相对
首地址
的偏移量,就可以从内存中获取到这个元素。计算方法如下num[i]_add =base_add + i*type_size
。通过这个计算方式可以看出在数组上进行随机访问时间复杂度为O(1)
的原因。 - 在数组插入元素的时间复杂度分析:假如在第
i
个位置插入元素target
,假如插入元素的位置刚好在数组的最后面是不需要移动数组中的任何元素,这也是最好最好时间复杂度
。最坏的情况下需要插入的元素的位置刚好在数组的第一个位置,为了保证数组的内存连续性,需要把数组中所有的元素统统向后移动一个位置。这也是最坏时间复杂度为o(n)
。平均时间复杂度
数组中有n个元素把一个元素插入数组中是等概率事件都为1/n
,那么插入元素的函数为f(n) = (1/n)*(1+2+3+.....+n)
,求和之后得到的平均时间复杂度为T(n)= o(n)
。 - 在数组中删除元素的时间复杂度与在数组中插入元素的
最好时间复杂度、最坏时间复杂度、平均时间复杂度
相同。 - 数组与
ArrayList
的区别,ArrayList
封装了数组很多底层的操作,包括插入、删除、扩容
等,ArrayList
支持动态扩容。扩容后的容量会变为原来的1.5倍,在这个过程中会设计到数组中元素的移动。因此这也是阿里巴巴编程手册建议在知道元素的个数的情况下,初始化的时候指定大小的原因。
三、Leetcode练习题目
-
-
算法思路分析以及题解
/** * 给你一个整数数组 A,只有可以将其划分为三个和相等的非空部分时才返回 true,否则返回 false。 * <p> * 形式上,如果可以找出索引 i+1 < j 且满足 (A[0] + A[1] + ... + A[i] == A[i+1] + A[i+2] + ... + A[j-1] == A[j] + A[j-1] + ... + A[A.length - 1]) 就可以将数组三等分。 * <p> * * <p> * 示例 1: * <p> * 输入:[0,2,1,-6,6,-7,9,1,2,0,1] * 输出:true * 解释:0 + 2 + 1 = -6 + 6 - 7 + 9 + 1 = 2 + 0 + 1 * 示例 2: * <p> * 输入:[0,2,1,-6,6,7,9,-1,2,0,1] * 输出:false * 示例 3: * <p> * 输入:[3,3,6,5,-2,2,5,1,-9,4] * 输出:true * 解释:3 + 3 = 6 = 5 - 2 + 2 + 5 + 1 - 9 + 4 * * <p> * 提示: * <p> * 3 <= A.length <= 50000 * -10^4 <= A[i] <= 10^4 * <p> * 解题思路: * 1、对数据累加求和,假如累加之后的和可以被3整除,说明有可能被平均的分为三等份。否则不能被分为三等分。 * 2、在能被三整除的情况下,除3的结果就是每一段分割之后的结果。 * 3、由于能被三整除,双指针查找。只要前后两端累加的结果等于sum/3,那么中间一段一定等于sum/3。 * * 一、时间复杂度分析 * 1、遍历一遍求和时间复杂度O(n) n为数据的大小 * 2、双指针查询结果的时候。最好O(1),最差O(n)。 * 3、所以时间复杂度为O(n) * 二、空间复杂度 * 1、常量空间复杂度O(1) */ public class Solution { public static boolean canThreePartsEqualSum(int[] A) { if (A == null || A.length < 3) { return false; } int sum = 0; for (int i = 0; i < A.length; i++) { sum += A[i]; } if (sum%3 != 0){ return false; } //双指针查找 int i = 0, j = A.length - 1; int leftSum = A[i],rightSum = A[j],avg = sum/3; while (i +1 < j) { if (leftSum == avg && rightSum == avg){ return true; } if (leftSum != avg){ leftSum += A[++i]; } if (rightSum != avg){ rightSum += A[--j]; } } return false; } }
-
-
-
算法思路分析以及题解
/** * 给定正整数数组 A,A[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的距离为 j - i。 * * 一对景点(i < j)组成的观光组合的得分为(A[i] + A[j] + i - j):景点的评分之和减去它们两者之间的距离。 * * 返回一对观光景点能取得的最高分。 * * * * 示例: * * 输入:[8,1,5,2,6] * 输出:11 * 解释:i = 0, j = 2, A[i] + A[j] + i - j = 8 + 5 + 0 - 2 = 11 * * * 提示: * * 2 <= A.length <= 50000 * 1 <= A[i] <= 1000 * * 解题思路: * 一、暴力解题 * 1、双重循环,遍历数组。 * 2、时间复杂度O(n^2) * 3、空间复杂度O(1) * * 二、优化思路 * 1、题目需要求出 result = A[i] + A[j] + i - j,拆分一波result = A[i]+i+A[j]-j。 * 2、在上述的关系式中对于计算过程中数据下标为j的数字。A[j] - j 是一个固定值。要result最大只需要A[i]+i最大即可。 * 3、条件2只是对数组中的任意一个数据,那么要求全局的最大值只需要遍历一遍数据把最大的result保存下来即可。 * 4、时间复杂度遍历一遍O(n)、空间复杂度O(1) */ public class Solution { public int maxScoreSightseeingPair(int[] A) { if (A == null){ return -1; } //只有一个元素直接返回0 int result = 0; //初始化第一个元素 int maxBefore = A[0]; int len = A.length; for (int i = 1; i < len; i++) { // 获取到当前的最大值 result = Math.max(result,maxBefore + A[i] - i); // 更新A[i]+i的最大值 maxBefore = Math.max(maxBefore,A[i] + i); } return result; } }
-