数组
数组理论
数组是内存上的一个连续的空间,地址是连续的,用于存储数据。
int[][] array = new [2][3];
声明并初始化一个二维数组,代表是一个2行3列的二维数组。
Collections中的ArrayList 底层也是一个可变的Object数组。
数组
####数组内置方法
在Java中,数组是基本的数据结构之一,提供了一些内置的方法来操作数组元素。以下是一些常用的数组方法:
- 长度获取:
length
:这是数组的一个属性,用于获取数组的长度,即数组中元素的数量。
- 元素克隆:
clone()
:返回数组的一个副本。
- 排序:
sort()
:数组元素的排序方法。对于整数数组,可以直接使用sort()
方法进行排序。
- 二分查找:
binarySearch(Object a, Object key)
:在给定的数组a
中使用二分查找算法搜索key
。注意,数组必须先排序。
- 填充:
fill(int a, int b, int val)
:从索引a
到索引b
填充数组元素val
。
- 复制:
copyOf(int[] original, int newLength)
:返回数组的副本,长度为newLength
。copyOfRange(int[] original, int from, int to)
:从原始数组中复制从from
到to
(不包括to
)的元素到新数组。
- 比较:
equals(Object anArray)
:比较两个数组是否相等。
- 查找特定元素:
indexOf(int a, int val)
:返回数组中第一次出现的val
的索引。lastIndexOf(int a, int val)
:返回数组中最后一次出现的val
的索引。
- 数组转换:
toString()
:返回数组内容的字符串表示。
- 多维数组元素获取和设置:
- 对于多维数组,可以通过索引多次调用
get
和set
方法来获取和设置特定位置的元素。
- 对于多维数组,可以通过索引多次调用
数组静态方法
在Java中,java.util.Arrays
类提供了一组静态方法来操作数组。以下是一些常用的 java.util.Arrays
静态方法:
- 排序:
sort(Object[] a)
:对对象数组进行升序排序。sort(int[] a)
:对整型数组进行升序排序。sort(long[] a)
:对长整型数组进行升序排序。sort(short[] a)
:对短整型数组进行升序排序。sort(char[] a)
:对字符数组进行升序排序。sort(byte[] a)
:对字节数组进行升序排序。sort(float[] a)
:对浮点型数组进行升序排序。sort(double[] a)
:对双精度浮点型数组进行升序排序。sort(Object[] a, Comparator c)
:使用自定义比较器对对象数组进行排序。
- 二分查找:
binarySearch(Object[] a, Object key)
:在已排序的对象数组中进行二分查找。
- 填充:
fill(Object[] a, Object val)
:用指定值填充数组。fill(int[] a, int val)
:用指定整数值填充整型数组。
- 复制:
copyOf(Object[] original, int newLength)
:创建一个新的数组,包含原数组的一部分或全部元素。copyOfRange(Object[] original, int from, int to)
:创建一个新的数组,包含原数组从from
到to - 1
的元素。
- 比较:
equals(Object[] a, Object[] a2)
:比较两个数组是否相等。
- 查找元素:
indexOf(Object[] a, Object aElement)
:返回指定元素在数组中第一次出现的索引。lastIndexOf(Object[] a, Object aElement)
:返回指定元素在数组中最后一次出现的索引。
- 数组转置:
transpose(double[][] a)
:转置二维数组。
- 深度相等:
deepEquals(Object[] a, Object a2)
:比较两个对象数组是否深度相等。
- 设置/获取数组元素:
setAll(int[] array, IntUnaryOperator generator)
:为整型数组的每个元素设置新值。setAll(Object[] array, IntFunction generator)
:为对象数组的每个元素设置新值。
- 并行排序:
parallelSort(Object[] a)
:使用并行排序对对象数组进行排序。
- 流操作:
stream(Object[] array)
:为对象数组创建一个流。
- 散布:
setAll(Object[] array, IntFunction generator)
:为数组的每个位置设置一个值,该值由提供的函数生成。
- 数组深拷贝:
deepCopyOf(Object[] original)
:创建对象数组的深拷贝。
ArrayList
ArrayList的扩容机制: 在声明时并不赋给他空间,在插入第一个元素时,容量扩展到10,每次扩容增大到之前的1.5倍左右
int newCapacity = oldCapacity + (oldCapacity >> 1);
####ArrayList常用方法:
ArrayList<Integer> array = new ArrayList<>();
ArrayList
是 Java 中的一个灵活且功能丰富的集合类,提供了许多用于操作列表的方法。以下是一些常用的 ArrayList
方法:
- 添加元素:
add(E e)
: 在列表末尾添加一个元素。add(int index, E element)
: 在指定位置插入一个元素。
- 获取元素:
get(int index)
: 返回指定位置的元素。
- 修改元素:
set(int index, E element)
: 用指定元素替换列表中指定位置的元素。
- 删除元素:
remove(int index)
: 删除指定位置的元素,并返回被删除的元素。remove(Object o)
: 删除列表中第一次出现的指定元素。
- 列表大小:
size()
: 返回列表中的元素数量。
- 容量管理:
trimToSize()
: 将列表的容量调整为列表的当前大小。ensureCapacity(int minCapacity)
: 如有必要,增加列表的容量以至少满足最小容量。
- 空检查:
isEmpty()
: 如果列表为空,则返回true
。
- 最大和最小值:
max()
: 返回列表中的最大元素。min()
: 返回列表中的最小元素。
- 列表遍历:
- 使用 for-each 循环或
Iterator
来遍历列表。
- 使用 for-each 循环或
- 排序:
sort(Comparator<? super E> c)
: 根据指定的比较器对列表进行排序。
- 子列表操作:
subList(int fromIndex, int toIndex)
: 返回从fromIndex
(包括)到toIndex
(不包括)的列表视图。
- 清空列表:
clear()
: 移除列表中的所有元素。
- 克隆:
clone()
: 返回列表的一个副本。
- 查找元素:
indexOf(Object o)
: 返回列表中第一次出现的指定元素的索引。lastIndexOf(Object o)
: 返回列表中最后一次出现的指定元素的索引。
- 集合操作:
contains(Object o)
: 如果列表包含指定元素,则返回true
。
- 转换为数组:
toArray()
: 将列表转换为数组。toArray(T[] a)
: 将列表转换为指定类型的数组。
704.二分查找
二分查找法,把已经排序好的数组 每次都从中间分开,if target
> mid
就移动left
, if target
< mid
,then move right
(按照升序排序)
值得注意的是 左闭右闭 还是 左闭右开 还有对 循环条件的判断
左闭右闭
left = 0
,right = nums.length-1
, while(left <= right)
class Solution {
public int search(int[] nums, int target) {
int left = 0,right=nums.length-1;
while(left <= right){
int mid = (left + right) >> 1;
if(target > nums[mid]){
left = mid + 1;
}else if(target < nums[mid]){
right = mid - 1;
}else{
return mid;
}
}
return -1;
}
}
####左闭右开
left = 0
, right = nums.length
, while(left < right)
class Solution {
public int search(int[] nums, int target) {
int left = 0,right=nums.length;
while(left < right){
int mid = (left + right) >> 1;
if(target > nums[mid]){
left = mid + 1;
}else if(target < nums[mid]){
right = mid;
}else{
return mid;
}
}
return -1;
}
}
27. 移除元素
数组在声明大小之后不可变,无法删除,只能覆盖
暴力解法
时间超限
class Solution {
public int removeElement(int[] nums, int val) {
int size = nums.length;
for(int i = 0; i < nums.length; i++){
if(nums[i] == val){//发现有相同的,集体前移
for(int j = i+1;j < nums.length;j++ ){
nums[j-1] = nums[j];
}
}
i--;//向前移动1位,需要重新检查该位
size --;//长短 -1
}
return size;
}
}
双指针
快慢指针
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针
- 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
- 慢指针:指向更新 新数组下标的位置
class Solution {
public int removeElement(int[] nums, int val) {
int slowIndex = 0;
for(int fastIndex = 0; fastIndex < nums.length; fastIndex ++){
if(nums[fastIndex] != val){
nums[slowIndex] = nums[fastIndex];
slowIndex ++;
}
}
return slowIndex;
}
}
35. 搜索插入位置
左闭右闭
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while(left <= right){
int mid = (left + right) >> 1;
if(target > nums[mid]){
left = mid + 1;
}else if(target < nums[mid]){
right = mid - 1;
}else{
return mid;
}
}
return right==-1 ? 0 : left;//如果找不到,此时 left > right;
}
}
####左闭右开
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length;
while(left < right){//二分查找,如果能找到的话
int mid = (left + right) >> 1;
if(target > nums[mid]){
left = mid + 1;
}else if(target < nums[mid]){
right = mid;
}else{
return mid;
}
}
return right==0 ? 0 : right;//如果找不到,且此时 left=right=0,此时只能在0插入;否则直接在right插入因为right是开区间
}
}
二分查找:可以扫描两次 分别确定 左边界和右边界
先找到情况条件:
1.target 不在 数组范围中 返回{-1,-1}
2.target 在数组范围中,但不在数组元素中,返回{-1,-1}
3.target 在数组范围且在元素中
第一次写法:
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = 0,right = nums.length -1 ;
//扫描右边界
int rightBorder = -2;
while(left <= right){
int mid = (left + right) >> 1;
if(target < nums[mid]){
right = mid - 1;
}else{
left = mid + 1;
rightBorder = mid;
}
}
//扫描左边界
int leftBorder = -2;
left = 0;
right = nums.length -1 ;
while(left <= right){
int mid = (left + right) >> 1;
if(target > nums[mid]){
left = mid + 1;
}else{
right = mid - 1;
leftBorder = mid;
}
}
//如果扫描后 不为target 返回{-1,-1}
if(rightBorder < leftBorder) return new int[] {-1,-1};
if (leftBorder == -2 || rightBorder == -2) return new int[] {-1, -1};
else return new int[] {leftBorder,rightBorder};
}
}
第二次写法
class Solution {
int findRightBorder(int[] nums, int target){
int rightBorder = -1;
int left = 0,right = nums.length -1;
while(left <= right){
int mid = (left + right) >> 1;
if(target < nums[mid]){
right = mid - 1;
}else{
left = mid + 1;
rightBorder = mid;
}
}
return rightBorder;
}
int findLeftBorder(int[] nums, int target){
int leftBorder = -1;
int left = 0,right = nums.length -1;
while(left <= right){
int mid = (left + right) >> 1;
if(target > nums[mid]){
left = mid + 1;
}else{
right = mid - 1;
leftBorder = mid;
}
}
return leftBorder;
}
public int[] searchRange(int[] nums, int target) {
int rightBorder = findRightBorder(nums,target);
int leftBorder = findLeftBorder(nums,target);
if(leftBorder > rightBorder) return new int[] {-1,-1};
else if (leftBorder == -1 || rightBorder == -1) return new int[] {-1, -1};
else return new int[] {leftBorder,rightBorder};
}
}