桶的思想
考虑使用情况
- 在数组内数据不是很大
a[i] ≤ a[i].len
且a[i] ≥ 0
时可以考虑使用- 数组中元素都为正或都为负
Easy
题目描述
思路
- 把数组想象成一排座位,数组下标表示座位号,数组中的元素值想象成小朋友的名字(根据题意,会有重名),一开始小朋友们随意坐在椅子上。
- 我们的目标是让小朋友i要坐在i号椅子上(如:元素3要坐在
num[3]
上) - 遍历数组只要
i
号椅子上坐的不是i
(if(num[i] != i)
),那么去看看i号椅子上坐的是谁
- 如果i号椅子上坐的也是i(即出现同名情况),跳出循环即可
- 如果i号椅子上坐的不是i,那么将i与i号椅子上的元素交换(
exch()
)
代码
public int findRepeatNumber(int[] nums) {
int result = 0;
for (int i = 0; i < nums.length; i++) {
while(nums[i] != i){
if (nums[i] == nums[nums[i]]){
result = nums[i];
break;
}
exch(nums,i,nums[i]);
}
}
return result;
}
private void exch(int[] nums, int a, int b){
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
Medium
题目描述
思路
- 对于数组中的元素,因为所有元素都大于0(
nums[1] > 1 > 0
),所以可以使用正负来表示出现的次数,正表示还没出现过,负表示出现过一次,因为nums[1] > 1 > 0
,所以Math.abs(nums[i])
为元素原值,下文使用absx
来表示元素真正的值
- 对于大部分的元素(
absx != len
),nums[absx]
的正负可以表示x
出现的次数 - 当
x == nums.length
时数组会越界,此时将元素x
的出现次数在num[0]
中表示
- 由题意:元素可能出现两次或一次
- 当元素x第一次出现时将
num[i]
取负数 - 如果已经为负则表示,元素i已出现过,此次为第二次出现,将元素i加入list
代码
class Solution {
public List<Integer> findDuplicates(int[] nums) {
List<Integer> list = new ArrayList<>();
int len = nums.length;
for (int i = 0; i < len; i++){
int absx = Math.abs(nums[i]);
if (absx == len){
if (nums[0] < 0){
list.add(len);
} else{
nums[0] = - nums[0];
}
}else{
if (nums[absx] < 0){
list.add(absx);
} else{
nums[absx] = - nums[absx];
}
}
}
return list;
}
}
Hard
题目描述
思路
- 遍历数组若数组中没有1,那么1就是没有出现的最小的正整数。
- 如果有1
- 数据整理
- 数组中
a[i] <= 0
的数不会对结果造成影响。 - 当数组中的元素从1递增至
nums.length
时,可以得到最大的结果为nums.length + 1
,如当nums[] == {1,2,3,4,5}
时,缺失的第一个正数为6。所以a[i] > nums.length + 1
的数不会对结果造成影响。 - 由于数组容量的关系,我们把num.length+1单独讨论,即也将数组中的num.length+1当做不会对结果造成影响的数据
- 将不会对结果造成影响的数据全部置为1
- 至此数组中元素全部为正,且
1 <= nums[i] <= num.length
。 - 此后我们用
num[1..num.length-1]
的正负来表示[1…nums.length-1]的是否出现;使用num[0]
的正负来表示num.length-1
- 最后按照num[1…num.length-1],num[0]的顺序遍历数组,遇到的第一个大于0的数即为没有出现的最小的正整数,若全部小于0,则答案为nums.length + 1;
代码
class Solution {
public int firstMissingPositive(int[] nums) {
int count1 = 0;
for (int i = 0; i < nums.length; i++){
if (nums[i] == 1){
count1++;
}
}
if (count1 == 0) {
return 1;
}
for (int i = 0; i < nums.length; i++){
if (nums[i] <= 0 || nums[i] > nums.length){
nums[i] = 1;
}
}
for (int i = 0; i < nums.length; i++) {
int x = Math.abs(nums[i]);
if (x == nums.length){
nums[0] = - Math.abs(nums[0]);
} else {
nums[x] = - Math.abs(nums[x]);
}
}
for (int i = 1; i < nums.length; i++) {
if (nums[i] > 0){
return i;
}
}
if (nums[0] > 0){
return nums.length;
}
return nums.length+1;
}
}