136题 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
利用 260题:只出现一次的数字 III 所学的异或知识可以轻松解决该问题
class Solution {
public int singleNumber(int[] nums) {
int temp = 0;
for(int num: nums){
temp = temp^num ;
}
return temp;
}
}
287题 寻找重复数
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入: [1,3,4,2,2]
输出: 2
示例 2:
输入: [3,1,3,4,2]
输出: 3
说明:
1、不能更改原数组(假设数组是只读的)。
2、只能使用额外的 O(1) 的空间。
3、时间复杂度小于 O(n2) 。
4、数组中只有一个重复的数字,但它可能不止重复出现一次。
暴力解法
public int findDuplicate(int[] nums) {
for(int i=0;i<nums.length;i++) {
for(int j=i+1;j<nums.length;j++) {
if(nums[i]==nums[j]) {
return nums[i];
}
}
}
return 0;
}
结果可想而知
其他思路(只能针对重复一次,该题目无法通过)
该思路利用数组的数字在1到N。所有存在一个值被替换,则通过正常无重复状态与改被替换的差值求出重复的值。
public int findDuplicate(int[] nums) {
int temp = 0;
for(int num:nums){
temp = temp+num;
}
return nums.length+(temp-(1+nums.length)*nums.length/2);
}
官方解法
非常想吐槽官方的说明,都说好了不能修改原数组,为什么可以使用排序
方法一:排序 思路就不需要说清楚,就是排序之后规则
class Solution {
public int findDuplicate(int[] nums) {
Arrays.sort(nums);
for (int i = 1; i < nums.length; i++) {
if (nums[i] == nums[i-1]) {
return nums[i];
}
}
return -1;
}
}
方法二:集合 该方法其他不可取,说明里面明确了只能使用额外的 O(1) 的空间
class Solution {
public int findDuplicate(int[] nums) {
Set<Integer> seen = new HashSet<Integer>();
for (int num : nums) {
if (seen.contains(num)) {
return num;
}
seen.add(num);
}
return -1;
}
}
方法三:弗洛伊德的乌龟和兔子(循环检测)
class Solution {
public int findDuplicate(int[] nums) {
// Find the intersection point of the two runners.
int tortoise = nums[0];
int hare = nums[0];
do {
tortoise = nums[tortoise];
hare = nums[nums[hare]];
} while (tortoise != hare);
// Find the "entrance" to the cycle.
int ptr1 = nums[0];
int ptr2 = tortoise;
while (ptr1 != ptr2) {
ptr1 = nums[ptr1];
ptr2 = nums[ptr2];
}
return ptr1;
}
}
官方解释:
本算法关键就是重复数字会导致形成环,环解决就是通过快慢指针。然后该重复数组就是换的入口。
参考资料: 快慢指针判断单向链表是否有环及找环入口
通过参考资料可以弄明白,索引和数值可以认为链表,由于数值存在重复所以会回到原来相同所以位置。所以形成的环。
所以代码分成两个部分
第一次相遇
do {
tortoise = nums[tortoise];
hare = nums[nums[hare]];
} while (tortoise != hare);
第二次快指针改为步数为1,直到相遇
int ptr1 = nums[0];
int ptr2 = tortoise;
while (ptr1 != ptr2) {
ptr1 = nums[ptr1];
ptr2 = nums[ptr2];
}