题解报告LeetCode#41:缺失的第一个正数
思路:
- 本题的难点在:只能使用常数级别的额外空间,在这个限制下本题的思路有一个非正式的名称:原地哈希。
- 由于题目要求我们「只能使用常数级别的空间」,而要找的数一定在
[1, N + 1]
左闭右闭(这里 N 是数组的长度)这个区间里。因此,我们可以就把原始的数组当做哈希表来使用。事实上,哈希表其实本身也是一个数组; - 我们要找的数就在
[1, N + 1]
里,最后N + 1
这个元素我们不用找。因为在前面的 N 个元素都找不到的情况下,我们才返回N + 1
; - 那么,我们可以采取这样的思路:就把 1 这个数放到下标为 0 的位置, 2 这个数放到下标为 1 的位置,按照这种思路整理一遍数组。然后我们再遍历一次数组,第 1 个遇到的它的值不等于下标的那个数,就是我们要找的缺失的第一个正数。
- 这个思想就相当于我们自己编写哈希函数,这个哈希函数的规则特别简单,那就是数值为 i 的数映射到下标为
i - 1
的位置。
其实这里你最主要就是去了解题意中[7,8,9,11,12]
中这个例子,这个例子在下面代码中的while
一次都没覆盖到,再之后的for判断返回值当然返回 1 咯。
代码:
class Solution {
public int firstMissingPositive(int[] nums) {
int len = nums.length;
for (int i = 0; i < len; i ++) {
while (nums[i] >= 1 && nums[i] <= len && nums[nums[i] - 1] != nums[i]) {
// 满足在指定范围内、并且没有放在正确的位置上,才交换
// 例如:数值 3 应该放在索引 2 的位置上
swap(nums, nums[i] - 1, i);
}
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
}
// 都正确则返回数组长度 + 1
return len + 1;
}
private void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}
题解报告LeetCode#442:数组中的重复数据
思路:
自己的解法和威哥的解法其实大同小异,都用到了原地哈希的思想,也就是将元素放到它本来应该身处的位置上去。
代码:
class Solution {
public List<Integer> findDuplicates(int[] nums) {
List<Integer> res = new ArrayList<>();
int len = nums.length;
for (int i = 0; i < len; i++) {
while (nums[i] > 0 && nums[i] - 1 != i) {
if (nums[nums[i] - 1] == nums[i]) {
res.add(nums[i]);
// 将重复的元素替换为负数做标记
nums[i] = -1;
break;
}
swap(nums, nums[i] - 1, i);
}
}
return res;
}
private void swap (int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}
他山之玉:
public class Solution {
public List<Integer> findDuplicates(int[] nums) {
List<Integer> res = new ArrayList<>();
int len = nums.length;
for (int i = 0; i < len; i++) {
while (nums[nums[i] - 1] != nums[i]) {
swap(nums, i, nums[i] - 1);
}
}
for (int i = 0; i < len; i++) {
if (nums[i] - 1 != i) {
res.add(nums[i]);
}
}
return res;
}
private void swap (int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}
题解报告LeetCode#448:找到数组中消失的数字
思路:原地哈希
代码:
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
List<Integer> res = new ArrayList<>();
int len = nums.length;
for (int i = 0; i < len; i++) {
// 对应位置上的值不是它应该有的值时,进入一趟
while (nums[nums[i] - 1] != nums[i]) {
swap(nums, nums[i] - 1, i);
}
}
for (int i = 0; i < len; i++) {
if (nums[i] != i + 1) {
res.add(i + 1);
}
}
return res;
}
private void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}