算法通关村第二关——爱不起的数组
线性表
-
线性表的定义
具有相同特征数据元素的一个有限序列,其中所含元素的个数称为线性表的长度
-
语言实现的角度:一体式©和分离式(java)
-
存储的角度:顺序型和链表型
- 顺序型:将数据存放在一段固定的区间内
- 链表型:元素之间通过地址依次连接的
-
访问限制的角度:栈和队列
- 栈
- 队列
- Hash
-
扩容的角度
- 分离式结构顺序表,容量可以动态变化
- 每次固定数目的扩充
- 每次扩充一倍的存储空间
- 每个语言的扩充策略均不一样
-
数组
定义:线性表最基本的结构。元素是一个紧密在一起的序列。相互之间不需要记录彼此的关系就能访问
索引:数组的索引是从0开始
注意:
-
数组的空间不一定是满的,即size(数据个数的变量)不等于length(数组长度)
-
数组的初始化值为0
-
初始化必须是连续的初始化,中间不可以出现空缺的情况,但是尾部是有空缺的情况
-
数组的创建和初始化
//1.初始化1 int[] arr = new int[10]; for (int i = 0; i < arr.length; i++) { arr[i]= i; } //2.初始化2 int[] arrs = new int[]{0,1,2,3,4,5,6,7,8};
-
查找一个元素
/** * 查找元素 * @param * @return */ public static int findByElement (int[] arr,int size, int key) { for (int i = 0; i < size; i++) { if (arr[i] ==key){ return i; }else if (arr[i] >=key){ return -1; } } return -1; }
-
增加一个元素
/** * @param arr * @param size 数组已经存储的元素数量 从编号1开始 * @param element 待插入的元素元素 * @return */ public static int addByElementSequence2(int[] arr, int size, int element) { //size表示元素的数量,arr.length表示数组容量,都是从1开始编号 if (size >= arr.length){ throw new IllegalArgumentException("Add failed. Array is full."); } for (int i = size; i > 0; i--) { if (arr[i-1]> element){ arr[i] = arr[i-1]; }else { arr[i] = element; } } return size+1; }
-
删除元素
/** * 遍历数组,如果发现目标元素,则将其删除, * 数组的删除就是从目标元素开始,用后续元素依次覆盖前继元素 * * @param arr 数组 * @param size 数组中的元素个数 * @param key 要删除的目标值 */ public static int removeByElement(int[] arr, int size, int key) { int index = -1; for (int i = 0; i < size; i++) { if (arr[i] == key) { index = i; break; } } if (index != -1) { for (int i = index + 1; i < size; i++) arr[i - 1] = arr[i]; size--; } return size; }
算法热身—单调数组问题
题目:LeetCode:896,判断该数组是否为单调数组
思路:题目简单,但是想要时间复杂度降低需要两个标识
解法:
public boolean isMonotonic(int[] nums) {
boolean inc = true, dec = true;
int n = nums.length;
for (int i = 0; i < n - 1; ++i) {
if (nums[i] > nums[i + 1]) {
inc = false;
}
if (nums[i] < nums[i + 1]) {
dec = false;
}
}
return inc || dec;
}
题目:LeetCode:35. 给定一个排列数组和目标值,在数组中找到目标值,并返回索引,如果目标值不存在数组中,则返回他顺序插入的位置
思路:高阶思想,利用二分查找来进行查询
解法:
-
二分法
class Solution { public int searchInsert(int[] nums, int target) { int n = nums.length; int left = 0, right = n - 1, ans = n; while (left <= right) { int mid = ((right - left) >> 1) + left; if (target <= nums[mid]) { ans = mid; right = mid - 1; } else { left = mid + 1; } } return ans; } }
算法热身—数组合并专题
题目:LeetCode:88,合并两个有序数组,使得合并完之后还是有序数组
思路:常规思路没什么好说的,关键是空间复杂度低的高阶思路:向后插入,因为两个合并的都是有序数组,所以他们的最大值一定在最后
解法:
-
向后插入
/** * 方法2:两个数组从后向前逐步合并 * * @param nums1 * @param nums1_len * @param nums2 * @param nums2_len */ public static void merge2(int[] nums1, int nums1_len, int[] nums2, int nums2_len) { int i = nums1_len + nums2_len - 1; int len1 = nums1_len - 1, len2 = nums2_len - 1; while (len1 >= 0 && len2 >= 0) { if (nums1[len1] <= nums2[len2]) nums1[i--] = nums2[len2--]; else if (nums1[len1] > nums2[len2]) nums1[i--] = nums1[len1--]; } //假如A或者B数组还有剩余 while (len2 != -1) nums1[i--] = nums2[len2--]; while (len1 != -1) nums1[i--] = nums1[len1--]; }