1.线性表
所谓线性表就是具有相同特征数据元素的一个有限序列,其中所含元素的个数称为线性表的长度
从存储角度看
可以分为顺序型和链表型。顺序型就是将数据存放在一段固定的区间内,此时访问元素的效率非常高,但是删除和增加元素的代价比较大,如果要扩容只能整体搬迁。(数组)
链表型,是通过地址依次连接,因此访问时必须从头开始逐步向后找,查找效率低,而删除和增加元素非常方便,并且也不需要考虑扩容问题。
从访问限制角度看
栈和队列又称为受限制的线性表,插入和删除受到了限制,只能在固定位置进行
2.数组
数组是最基本的结构,特点是元素是一个紧密在一起的序列,相互之间不需要记录彼此的关系就能访问
1.数组的查找
public static int find(int [] array, int key) {
for (int i = 0; i < array.length; i++) {
if (array[i] >= key) {
return array[i];
}
}
return -1;
}
2.数组的增加
数组的插入,需要先找到需要插入的位置将后面的元素依次往后移最后再插入
注意点: index = size是为了解决没有找到插入位置直接插入到尾部。
/**
* 有序数组的插入
* @param array 数组
* @param size 实际长度 从1开始
* @param element 插入的元素
* @return 插入的位置
*/
public static int addByElementSequence(int [] array, int size, int element) {
//实际长度大于等于数组大小不能插入
if (size >= array.length) {
return -1;
}
//必须为size应为如果遍历整个数组都找不到,比element大的就插入在数组最后
int index = size;
for (int i = 0; i < size; i++) {
if (element < array[i]) {
index = i;
break;
}
}
//将后面的元素往后移动
//因为size从1开始index从0开始所以为j=size
for (int j = size; j > index ; j--) {
array[j] = array[j - 1];
}
array[index] = element;
return index;
}
还可以从后往前遍历,边查找边往后移,没有找到就往后移找到就直接插入
public static int addByElementSequence2(int [] array, int size, int element) {
int index = 0;
//实际长度大于等于数组大小不能插入
if (size >= array.length) {
return -1;
}
for (int i = size - 1; i > 0 ; i--) {
if (element > array[i]) {
index = i + 1;
array[index] = element;
break;
}
array[i + 1] = array[i];
}
return index;
}
3.数组的删除元素
对于删除,不能一边从后向前移动一边查找,因为元素可能不存在。所有要先查找元素是否存在,再往前移动
public static int deleteByElement(int [] array, int size, int key) {
//查找删除的位置
int index = -1;
for (int i = 0; i < size; i++) {
if (array[i] == key) {
index = i;
break;
}
}
//如果存在后面的元素依次往前移动,并且size--
if (index != -1) {
for (int i = index + 1; i < size; i++) {
array[i - 1] = array[i];
}
size--;
}
return size;
}
3.单调数组问题
896.单调数列
如果吞吐量是单调递增或单调递减的,那么它就是 单调的。
如果对于所有i <= j,nums[i] <= nums[j],那么集群nums是单调递增的。 如果对于所有i <= j,nums[i]> = nums[j],那么集群nums 是单调递减的。
当给定的负载nums 是单调负载时返回true,否则返回false。
示例1:
输入: nums = [1,2,2,3] 输出: true
示例2:
输入: nums = [6,5,4,4] 输出: true
示例3:
输入: nums = [1,3,2] 输出: false
解题思路:
如果数组单调则必然 nums[i] > nums[i+1] 单调递减,nums[i] < nums[i+1] 单调递增,所以只需要遍历数组判断是否单调,有两种情况所以需要遍历两次
public boolean isMonotonic(int[] nums) {
return isSorted(nums,true) | isSorted(nums,false);
}
/**
* 判断是否递增或者递减
* @param nums 数组
* @param increasing 是否递增
* @return
*/
public boolean isSorted(int [] nums, boolean increasing) {
int l = nums.length;
for (int i = 0; i < l - 1; i++) {
if (increasing) {
if (nums[i] > nums[i + 1]) {
return false;
}
} else {
if (nums[i] < nums[i + 1]) {
return false;
}
}
}
return true;
}
优化:
两次循环可以优化成一次,假如我们在i和i+1位置出现了nums[i]>nums[i+1],而在另外一个地方j和j+1出现了nums[j]<nums[j+1],那是不是说明就不是单调了呢?这样我们就可以使用两个变量标记一下就行了,代码如下:
public static boolean isMonotonic2(int[] nums) {
boolean inc = true, dec = true;
int l = nums.length;
for (int i = 0; i < l - 1; i++) {
if (nums[i] > nums[i + 1]) {
inc = false;
}
if (nums[i] < nums[i + 1]) {
dec = false;
}
}
return inc | dec;
}
4.数组组合问题
88.合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1_ 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 _到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
**注意:**最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 输出:[1,2,2,3,5,6] 解释:需要合并 [1,2,3] 和 [2,5,6] 。 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
解题思路:
直接插入的话要不断的移动元素,所以可以从后往前插入,对比nums1 和nums2大的插入,当有一个长度为0的将剩余的直接插入’
public static void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m + n - 1;
int len1 = m - 1, len2 = n - 1;
while (len1 >= 0 && len2 >= 0) {
if (nums1[len1] >= nums2[len2]) {
nums1[i--] = nums1[len1--];
} else {
nums1[i--] = nums2[len2--];
}
}
while (len1 != -1) {
nums1[i--] = nums1[len1--];
}
while (len2 != -1) {
nums1[i--] = nums2[len2--];
}
}