1. 数组中随机的重复数字
1.1 问题描述
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例
输入:
[2, 3, 1, 0, 2, 5, 3]
输出: 2 或 3
1.2 解题思路
- 可以利用Set集合数据不重复的特性,遍历数组中所有元素,并将元素放入到Set集合中,当Set失败时,说明重复了,将这个元素返回即可。
- 充分利用好条件,长度为n的数组,数组中元素只能在0-n之间,那么可以根据元素中的数值,数值和下标Index一致就可以了,只要在要移动到的下标元素和要移动元素相同,说明就是有重复的元素,返回即可。
1.3 代码示例
1.3.1 Set方案
public int findRepeatNumber(int[] nums) {
if(nums.length <= 1) {
// 只有一个元素或是没有元素时直接返回,没有重复的
return -1;
}
// 缓存已经添加过的数字
Set<Integer> numCache = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if(!numCache.add(nums[i])) {
return nums[i];
}
}
return -1;
}
1.3.2 原地更新法
public int findRepeatNumber(int[] nums) {
if(nums.length <= 1) {
return -1;
}
for (int i = 0; i < nums.length; i++) {
// 当前下标的元素和下标不一致时进行元素移动
while(nums[i] != i) {
// 要移动的元素和移动到的位置上元素一样时说明重复了
if(nums[i] == nums[nums[i]]) {
return nums[i];
}
// 元素交换
int temp = nums[nums[i]];
nums[nums[i]] = nums[i];
nums[i] = temp;
}
}
return -1;
}
2. 素数个数
2.1 问题描述
求2 - n(n > 2的正整数)中有多少个素数。
示例
输入:
10
输出:
4
2.2 解题思路
- 埃式筛选法:通过已经过滤出来的素数去过滤掉其他的数字。
2.3 代码示例
public int eratosthenes(int n) {
// 定义n个boolean的数组,默认所有的数字都是素数
boolean[] isPrime = new boolean[n];
// 素数的个数
int count = 0;
// 从2开始,因为0和1都是非素数
for (int i = 2; i < n; i++) {
if(!isPrime[i]) {
count++;
for (int j = i * i; j < n; j+=i) {
// 因为到这个for循环了,那么i就是素数了,i * i就是合数,
// 因为有了其他的数可以由两个数相乘得到
isPrime[j] = true;
}
}
}
// 返回素数个数
return count;
}
3. 寻找数组的中心下标
3.1 问题描述
中心下标左边数据之和等于右边数据之和。存在则返回,存在多个则返回最左边的中心下标,不存在则返回-1
示例
输入:
[3,2,3]
输出:
1
3.2 解题思路
- 双指针法:左边数组之和 + 中心下标元素 = 右边数组之和 + 中心下标元素
3.3 代码示例
public int pivotIndex(int[] nums) {
// 开始时右边数据 = 数组元素之和
int rightSum = Arrays.stream(nums).sum();
// 开始时左边数据 = 0;
int leftSum = 0;
for (int i = 0; i < nums.length; i++) {
// 从0下标开始累加
leftSum += nums[i];
if (leftSum == rightSum) {
// 说明i已经是中心下标了
return i;
}
// 减去i包含i之前的元素之和
sum -= nums[i];
}
}