概述
二、数组
1、基础知识
静态数组
Java 数组 | 菜鸟教程
Arrays.XXX()
序号 | 方法和说明 |
---|---|
1 | public static int binarySearch(Object[] a, Object key) 用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。 |
2 | public static boolean equals(long[] a, long[] a2) 如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
3 | public static void fill(int[] a, int val) 将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
4 | public static void sort(Object[] a) 对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
xxx[] a = b.clone()
动态数组
ArrayList:Java ArrayList | 菜鸟教程
ArrayList 中的元素实际上是对象,如果我们要存储其他类型,而 <E> 只能为引用数据类型,这时我们就需要使用到基本类型的包装类。
方法 | 描述 |
---|---|
add() | 将元素插入到指定位置的 arraylist 中 |
addAll() | 添加集合中的所有元素到 arraylist 中 |
clear() | 删除 arraylist 中的所有元素 |
clone() | 复制一份 arraylist |
contains() | 判断元素是否在 arraylist |
get() | 通过索引值获取 arraylist 中的元素 |
indexOf() | 返回 arraylist 中元素的索引值 |
removeAll() | 删除存在于指定集合中的 arraylist 里的所有元素 |
remove() | 删除 arraylist 里的单个元素,参数为索引值 |
size() | 返回 arraylist 里元素数量 |
isEmpty() | 判断 arraylist 是否为空 |
subList() | 截取部分 arraylist 的元素 |
set() | 替换 arraylist 中指定索引的元素 |
sort() | Collections.sort(),可以对字符或数字列表进行排序。 |
toArray() | 将 arraylist 转换为静态数组 |
toString() | 将 arraylist 转换为字符串 |
ensureCapacity() | 设置指定容量大小的 arraylist |
lastIndexOf() | 返回指定元素在 arraylist 中最后一次出现的位置 |
retainAll() | 保留 arraylist 中在指定集合中也存在的那些元素 |
containsAll() | 查看 arraylist 是否包含指定集合中的所有元素 |
trimToSize() | 将 arraylist 中的容量调整为数组中的元素个数 |
removeRange() | 删除 arraylist 中指定索引之间存在的元素 |
replaceAll() | 将给定的操作内容替换掉数组中每一个元素 |
removeIf() | 删除所有满足特定条件的 arraylist 元素 |
forEach() | 遍历 arraylist 中每一个元素并执行特定操作 |
LinkedList:Java LinkedList | 菜鸟教程
- LinkedList 继承了 AbstractSequentialList 类。
- LinkedList 实现了 Queue 接口,可作为队列使用。
- LinkedList 实现了 List 接口,可进行列表的相关操作。
- LinkedList 实现了 Deque 接口,可作为队列使用。
- LinkedList 实现了 Cloneable 接口,可实现克隆。
- LinkedList 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。
// 引入 LinkedList 类
import java.util.LinkedList;
LinkedList<E> list = new LinkedList<E>(); // 普通创建方法
或者
LinkedList<E> list = new LinkedList(Collection<? extends E> c); // 使用集合创建链表
// 打印输出,格式:[x, y, z]
System.out.println(sites);
方法 | 描述 |
---|---|
public boolean add(E e) | 链表末尾添加元素,返回是否成功,成功为 true,失败为 false。 |
public void add(int index, E element) | 向指定位置插入元素。 |
public boolean addAll(Collection c) | 将一个集合的所有元素添加到链表后面,返回是否成功,成功为 true,失败为 false。 |
public boolean addAll(int index, Collection c) | 将一个集合的所有元素添加到链表的指定位置后面,返回是否成功,成功为 true,失败为 false。 |
public void addFirst(E e) | 元素添加到头部。 |
public void addLast(E e) | 元素添加到尾部。 |
public boolean offer(E e) | 向链表末尾添加元素,返回是否成功,成功为 true,失败为 false。 |
public boolean offerFirst(E e) | 头部插入元素,返回是否成功,成功为 true,失败为 false。 |
public boolean offerLast(E e) | 尾部插入元素,返回是否成功,成功为 true,失败为 false。 |
public void clear() | 清空链表。 |
public E removeFirst() | 删除并返回第一个元素。 |
public E removeLast() | 删除并返回最后一个元素。 |
public boolean remove(Object o) | 删除某一元素,返回是否成功,成功为 true,失败为 false。 |
public E remove(int index) | 删除指定位置的元素。 |
public E poll() | 删除并返回第一个元素。 |
public E remove() | 删除并返回第一个元素。 |
public boolean contains(Object o) | 判断是否含有某一元素。 |
public E get(int index) | 返回指定位置的元素。 |
public E getFirst() | 返回第一个元素。 |
public E getLast() | 返回最后一个元素。 |
public int indexOf(Object o) | 查找指定元素从前往后第一次出现的索引。 |
public int lastIndexOf(Object o) | 查找指定元素最后一次出现的索引。 |
public E peek() | 返回第一个元素。 |
public E element() | 返回第一个元素。 |
public E peekFirst() | 返回头部元素。 |
public E peekLast() | 返回尾部元素。 |
public E set(int index, E element) | 设置指定位置的元素。 |
public Object clone() | 克隆该列表。 |
public Iterator descendingIterator() | 返回倒序迭代器。 |
public int size() | 返回链表元素个数。 |
public ListIterator listIterator(int index) | 返回从指定位置开始到末尾的迭代器。 |
public Object[] toArray() | 返回一个由链表元素组成的数组。 |
public T[] toArray(T[] a) | 返回一个由链表元素转换类型而成的数组。 |
以下情况使用 ArrayList :
- 频繁访问列表中的某一个元素。
- 只需要在列表末尾进行添加和删除元素操作。
以下情况使用 LinkedList :
- 你需要通过循环迭代来访问列表中的某些元素。
- 需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。
2、基本题型
(1)双指针
一般数组中的数为正整数时,可以用双指针
反向双指针
剑指 Offer II 006. 排序数组中两个数字之和
class Solution {
//双指针
public int[] twoSum(int[] numbers, int target) {
int l = 0;
int r = numbers.length - 1;
while (l < r && numbers[l] + numbers[r] != target) {
if (numbers[l] + numbers[r] < target) {
l++;
} else {
r--;
}
}
return new int[]{l, r};
}
}
也可以用哈希表
class Solution {
public int[] twoSum(int[] numbers, int target) {
//哈希
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < numbers.length; i++) {
if (map.containsKey(target - numbers[i])) {
return new int[]{map.get(target - numbers[i]), i};
} else {
map.put(numbers[i], i);
}
}
return new int[]{-1, -1};
}
}
剑指 Offer II 007. 数组中和为 0 的三个数
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// 用什么数据结构?动态数组
List<List<Integer>> res = new LinkedList<>();
//base case
if (nums.length < 3) return res;
//先排序 n·logn
Arrays.sort(nums);
//固定一个数,剩下用双指针
for (int i = 0; i < nums.length - 2; ) {
for (int j = i + 1, k = nums.length - 1; j < k; ) {
if ((nums[i] + nums[j] + nums[k]) < 0) {
++j;
} else if ((nums[i] + nums[j] + nums[k]) > 0) {
--k;
} else {
res.add(Arrays.asList(nums[i], nums[j], nums[k]));
//去重
int temp = nums[j];
while (nums[j] == temp && j < k) {
++j;
}
}
}
//去重
int temp = nums[i];
while (i < nums.length && nums[i] == temp) {
++i;
}
}
return res;
}
}
同向双指针(又称为“滑动窗口”)
一般为for+while结构
剑指 Offer II 008. 和大于等于 target 的最短子数组
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int i = 0;
int minLen = nums.length+1;
int sum = 0;
for (int j = 0; j < nums.length; j++) {
sum += nums[j];
while (i <= j && sum >= target) {
minLen = Math.min(minLen, j - i + 1);
sum -= nums[i++];
}
}
return minLen == nums.length+1 ? 0 : minLen;
}
}
方法二:前缀和 + 二分查找
class Solution {
public int minSubArrayLen(int s, int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int ans = Integer.MAX_VALUE;
int[] sums = new int[n + 1];
// 为了方便计算,令 size = n + 1
// sums[0] = 0 意味着前 0 个元素的前缀和为 0
// sums[1] = A[0] 前 1 个元素的前缀和为 A[0]
// 以此类推
for (int i = 1; i <= n; i++) {
sums[i] = sums[i - 1] + nums[i - 1];
}
for (int i = 1; i <= n; i++) {
int target = s + sums[i - 1];
int bound = Arrays.binarySearch(sums, target);
if (bound < 0) {
bound = -bound - 1;
}
if (bound <= n) {
ans = Math.min(ans, bound - (i - 1));
}
}
return ans == Integer.MAX_VALUE ? 0 : ans;
}
}
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/minimum-size-subarray-sum/solution/chang-du-zui-xiao-de-zi-shu-zu-by-leetcode-solutio/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer II 009. 乘积小于 K 的子数组
结构和上一道类似,注意数值范围
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
long mul = 1;
int i = 0;
int cnt = 0;
for (int j = 0; j < nums.length; ++j) {
mul *= nums[j];
while (i <= j && mul >= k) {
mul /= nums[i++];
}
cnt += (i <= j) ? j - i + 1 : 0;
}
return cnt;
}
}
法二:同样可以转化为前缀和,只是这里的前缀和需要通过log运算将乘积转化为求和
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
if (k == 0) {
return 0;
}
int n = nums.length;
double[] logPrefix = new double[n + 1];
for (int i = 0; i < n; i++) {
logPrefix[i + 1] = logPrefix[i] + Math.log(nums[i]);
}
double logk = Math.log(k);
int ret = 0;
for (int j = 0; j < n; j++) {
int l = 0;
int r = j + 1;
int idx = j + 1;
double val = logPrefix[j + 1] - logk + 1e-10;
while (l <= r) {
int mid = (l + r) / 2;
if (logPrefix[mid] > val) {
idx = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
ret += j + 1 - idx;
}
return ret;
}
}
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/subarray-product-less-than-k/solution/cheng-ji-xiao-yu-k-de-zi-shu-zu-by-leetc-92wl/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
(2)前缀和
若数组有可能是负数,需要使用前缀和方法
一维前缀和+HashMap
剑指 Offer II 010. 和为 k 的子数组
class Solution {
//前缀和解法
public int subarraySum(int[] nums, int k) {
//key: sum, value:count
Map<Integer, Integer> map = new HashMap<>();
int sum = 0;
int count = 0;
map.put(0, 1);
for (int num : nums) {
sum += num;
count += map.getOrDefault(sum - k, 0);
map.put(sum, map.getOrDefault(sum, 0) + 1);
}
return count;
}
}
基础解法是枚举
public class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
for (int start = 0; start < nums.length; ++start) {
int sum = 0;
for (int end = start; end >= 0; --end) {
sum += nums[end];
if (sum == k) {
count++;
}
}
}
return count;
}
}
剑指 Offer II 011. 0 和 1 个数相同的子数组
和上一题完全一样,只不过上一道求个数,这一道求长度,所以map里面存放的不一样,这里只存放第一次出现的和的索引值
class Solution {
public int findMaxLength(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
map.put(0, -1);
int sum = 0;
int maxLen = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i] == 0 ? -1 : 1;
map.putIfAbsent(sum,i);
maxLen = Math.max(maxLen, i - map.get(sum));
}
return maxLen;
}
}
剑指 Offer II 012. 左右两边子数组的和相等
class Solution {
public int pivotIndex(int[] nums) {
int sum = 0;
for (int num : nums) {
sum += num;
}
int temp = 0;
for (int i = 0; i < nums.length; i++) {
temp += nums[i];
if (temp - nums[i] == sum - temp) {
return i;
}
}
return -1;
}
}
二维前缀和
剑指 Offer II 013. 二维子矩阵的和
class NumMatrix {
private int[][] sums;
public NumMatrix(int[][] matrix) {
if (matrix.length == 0 || matrix[0].length == 0) {
return;
}
sums = new int[matrix.length + 1][matrix[0].length + 1];
for (int i = 0; i < matrix.length; i++) {
int rowSum = 0;
for (int j = 0; j < matrix[0].length; j++) {
rowSum += matrix[i][j];
sums[i + 1][j + 1] = sums[i][j + 1] + rowSum;
}
}
}
public int sumRegion(int row1, int col1, int row2, int col2) {
return sums[row1][col1] - sums[row1][col2 + 1] - sums[row2 + 1][col1] + sums[row2 + 1][col2 + 1];
}
}
最后
以上就是笨笨仙人掌为你收集整理的【剑指offer2】 chap2 数组二、数组的全部内容,希望文章能够帮你解决【剑指offer2】 chap2 数组二、数组所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复