1. 声明数组
声明数组:在Java中,可以使用以下语法声明数组:dataType[] arrayName;。例如,要声明一个整数数组,可以写int[] myArray;。 实例化数组:声明数组后,需要使用new关键字为其分配内存。例如:myArray = new int[10];。这将创建一个可以存储10个整数的数组。 初始化数组:可以在声明数组时初始化它,例如:int[] myArray = {1, 2, 3, 4, 5};。也可以在创建数组后单独初始化每个元素,例如:myArray[0] = 1;。 注意:声明时初始化:在声明数组的同时,就为数组分配空间并赋值。例如:
int[] arr = {1, 2, 3};
先声明,后初始化:先声明一个数组,然后再为数组的每个元素分配空间并赋值。例如:
java
Copy code
int[] arr = new int[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
不能将两种方法混合:int [] arr = new int[3];
arr = {1,2,3};
这种方法是错误的
访问数组元素:可以使用数组索引来访问数组元素。数组的索引从0开始,所以第一个元素的索引是0,第二个元素的索引是1,依此类推。例如,myArray[0]将访问数组的第一个元素。
数组长度:可以使用arrayName.length获取数组的长度。例如,myArray.length将返回数组myArray的长度。
多维数组:Java支持多维数组,最常见的是二维数组。例如,int[][] my2DArray = new int[10][5];创建了一个10行5列的二维数组。
遍历数组:可以使用for循环或者for-each循环来遍历数组。例如:
for(int i=0; i<myArray.length; i++) {
System.out.println(myArray[i]);
}
或者
for(int num : myArray) {
System.out.println(num);
}*/
2.Arrays常用操作
//1.sort():对数组进行排序
int[] arr3 = {3,2,1};
Arrays.sort(arr3);
/* arr现在是{1, 2, 3}*/
//2.toString():返回数组的字符串表示形式。
String str = Arrays.toString(arr3);
// str现在是"[1, 2, 3]"
/*在这个例子中,str是一个字符串,它的值是"[1, 2, 3]"。这个字符串的长度是9,因为它包含了9个字符:一个开方括号,三个数字,两个逗号,两个空格,和一个闭方括号。
每个数字在这个字符串中都是字符的一部分,而不是一个独立的整数。在Java中,字符串是由字符组成的,所以str中的"1"、"2"和"3"都是字符,而不是整数。
如果你想从这个字符串中获取整数,你需要进行一些处理,例如使用split()方法分割字符串,然后将每个分割后的字符串转换为整数。例如:*/
/*String str = "[1, 2, 3]";*/
str = str.replaceAll("\\[|\\]|\\s", ""); // 移除方括号和空格
//注意split返回的是string的数组
String[] numbers = str.split(","); // 使用逗号分割字符串
for (String number : numbers) {
int num = Integer.parseInt(number); // 将字符串转换为整数
System.out.println(num);
}
/*这段代码将输出:
Copy code
1
2
3
这样,你就可以从字符串中获取到每个数字作为一个整数。*/
//3.binarySearch():在已排序的数组中查找指定的元素。如果找到,返回元素的索引;如果找不到,返回负值。
int number = Arrays.binarySearch(arr3,2);
//number = 1
//4.equals()判断两个数组是否完全一致
int[] arr4 = {3,2,1};
boolean isEqual = Arrays.equals(arr4,arr3);
//isEqual = ture
//5.fill():使用指定的值填充整个数组或者数组的一部分。
Arrays.fill(arr4,1);
/*arr4 = {1,1,1}*/
//6.copyOf():复制数组的一部分或全部到一个新数组。
int[] arr5 = Arrays.copyOf(arr3,arr3.length);
/*arr5 = {3,2,1}*/
}
1. 两数之和
在Java中,我们可以使用HashMap
来存储数组中每个元素的值和它们对应的索引。这样,对于数组中的每个元素x
,我们可以快速检查哈希表中是否存在一个键值为target - x
的元素。如果存在,那么我们找到了一对数,它们的和为target
。
import java.util.HashMap;
class Solution {
public int[] twoSum(int[] nums, int target) {
// 创建一个HashMap来存储之前遍历过的数字和它们对应的索引
HashMap<Integer, Integer> map = new HashMap<>();
// 遍历数组中的每个元素
for (int i = 0; i < nums.length; i++) {
// 计算当前元素与目标值之间的差
int complement = target - nums[i];
// 检查这个差值是否已经在Map中,如果是,直接返回当前索引和差值对应的索引
if (map.containsKey(complement)) {
return new int[] { map.get(complement), i };
}
// 如果没有找到,将当前元素的值和索引存入Map中,以便后续查找
map.put(nums[i], i);
}
// 如果没有找到符合条件的两个数,则抛出异常
return new int[] {};
}
}
49. 字母异位词分组
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
if (strs == null || strs.length == 0) {
return new ArrayList<>();
}
Map<String, List<String>> map = new HashMap<>();
for (String s : strs) {
char[] ca = s.toCharArray();
Arrays.sort(ca);
String key = String.valueOf(ca);
if (!map.containsKey(key)) {
map.put(key, new ArrayList<>());
}
map.get(key).add(s);
}
return new ArrayList<>(map.values());
}
}
为了解决这个问题,我们可以采用一个高效的策略:对每个字符串按照字符排序,然后使用排序后的字符串作为键,将原始字符串添加到对应的列表中。这样,所有字母异位词都会有相同的排序字符串作为键,从而被归类到同一个列表中。
具体步骤如下:
- 创建一个哈希表(HashMap),键是字符串,值是字符串列表,用于存放归类后的字母异位词。
- 遍历给定的字符串数组
strs
。- 对每个字符串进行排序。
- 检查排序后的字符串是否已经作为键存在于哈希表中。
- 如果存在,将原字符串添加到对应的列表中。
- 如果不存在,创建一个新的列表,并将原字符串添加到列表中,然后将列表作为值,排序后的字符串作为键存入哈希表中。
- 最后,返回哈希表中所有值的集合,这就是分组后的字母异位词列表。
128. 最长连续序列
要实现一个时间复杂度为O(n)的算法来解决这个问题,我们可以利用哈希表(在Java中是HashSet
)来快速查找数组中的元素。基本思路是这样的:
- 首先,将所有的元素放入哈希表中,这样就可以在O(1)的时间复杂度内判断一个元素是否存在。
- 然后,遍历数组中的每个元素,对于每个元素,我们尝试向两边扩展序列,查看比当前元素小1的元素和比当前元素大1的元素是否存在于哈希表中,如果存在,就继续向该方向扩展,并从哈希表中移除已经访问过的元素,以避免重复计算。
- 记录并更新最长连续序列的长度。
这里需要注意的是,我们只从序列的第一个元素开始扩展,即只有当一个元素的前一个元素不存在于哈希表中时,才开始扩展。这样可以确保我们每个序列只会被扩展一次,保证了算法的时间复杂度为O(n)。
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> numSet = new HashSet<>();
//将所有的不重复的num加入到set中去。
for(int num: nums) {
numSet.add(num);
}
//最长的连续个数
int longestStreak = 0;
//遍历所有的set
for(int num : numSet) {
只有当num的前一个元素不存在时,才开始向后寻找连续序列
if(!numSet.contains(num - 1)) {
int curNum = num;
//将当前最长序列变成1,就是起始位置。
int curStreak = 1;
//在set中不断找比当前数大1的数
while(numSet.contains(curNum + 1)) {
//如果有,更新当前数,并且将当前最长的序列长度再加1
curNum += 1;
curStreak += 1;
}
//找到了一个最长序列,看看是不是整个nums数组最长的。
longestStreak = Math.max(longestStreak, curStreak);
}
}
return longestStreak;
}
}
// 只有当num的前一个元素不存在时,才开始向后寻找连续序列 为什么?
ChatGPT
ChatGPT
这个策略是为了确保算法的效率和防止重复计算,使得时间复杂度能够保持在O(n)。让我们详细解释一下这个过程。
当我们从一个数开始寻找连续序列时,如果这个数的前一个数也在数组中,意味着这个数已经是某个连续序列的一部分了。如果我们从这个数开始向两边扩展,那么这个连续序列的前半部分实际上是被重复计算的,因为从前一个数开始扩展时,这部分已经被计算过一次了。
通过只从序列的“起点”开始扩展(即这个数的前一个数不在数组中,表明这个数可能是一个连续序列的最小值),我们可以确保:
-
避免重复计算:每个连续序列只会被计算一次,即从它的最小值开始向上寻找连续的数。这样,每个数字在寻找连续序列时只会被访问和计算一次,避免了不必要的重复操作。
-
效率最高:由于每个序列只被计算一次,且哈希表的查找操作是O(1)的,因此整个算法可以在O(n)的时间复杂度内完成。这里n是数组中元素的数量。我们通过哈希表一次性将所有元素加入,然后遍历数组时,每个元素最多被访问一次(除非它是某个连续序列的一部分,在这种情况下,它在寻找过程中只被计算一次)。
举个例子,考虑数组[3, 4, 2, 1]
。按照上述策略,当我们遇到3
时,会检查2
是否在集合中。因为2
存在,我们就跳过3
不做处理(因为如果2
存在,那么从2
开始的序列肯定比从3
开始的要长)。当我们遇到4
时,检查3
发现存在,同样跳过。当我们到2
时,发现1
不存在,意味着2
可能是一个连续序列的起点,于是从2
开始向上寻找,直到4
,形成连续序列[2, 3, 4]
。最后,当处理到1
时,由于它的前一个数不存在,我们知道它是另一个序列的起点,但因为它自己就构成了一个长度为1的序列,所以这一步实际上没有扩展的必要。
240. 搜索二维矩阵
思路:
由于矩阵的行和列都是升序排列的,我们可以从右上角开始搜索。根据目标值与当前元素的比较,我们可以排除一整行或一整列。
- 初始化坐标: 将行坐标设置为0,列坐标设置为矩阵的最后一列。
- 比较并移动:
- 如果目标值等于当前元素,则返回
true
。 - 如果目标值小于当前元素,则向左移动一列。
- 如果目标值大于当前元素,则向下移动一行。
- 如果目标值等于当前元素,则返回
- 重复步骤2: 直到行坐标超出范围或列坐标超出范围。
但是如果从左上角开始搜索,则当目标值大于当前元素时,我们无法确定是向右移动还是向下移动,因为两个方向的元素都可能大于当前元素。
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length, n = matrix[0].length;
int row = 0, col = n - 1;
while (row < m && col >= 0) {
if (matrix[row][col] == target) {
return true; // 找到目标值
} else if (matrix[row][col] < target) {
row++; // 向下移动
} else {
col--; // 向左移动
}
}
return false; // 没有找到目标值
}
}