代码实现:
第一次想到用map,虽然能得到正确结果,但是不符合不用额外内存的要求
//用map 不符合不使用额外空间
public int singleNumber1(int[] nums) {
int temp = 0;
Map<Integer, Boolean> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(nums[i])) {
map.put(nums[i], false);
continue;
}
map.put(nums[i], true);
}
for (int i = 0; i < nums.length; i++) {
if (map.get(nums[i])) {
temp = nums[i];
break;
}
}
return temp;
}
第二次想到堆排序,堆排序时间复杂度是NLogN,空间复杂度是常数级别:
public static void main(String[] args) {
SingleNumber singleNumber = new SingleNumber();
int[] arr = {4, 1, 2, 1, 2};
singleNumber.singleNumber(arr);
}
//用堆排序,时间复杂度是 O(NLogN)
public int singleNumber2(int[] nums) {
heapSort(nums);
int temp = 0;
for (int i = 0; i < nums.length; i++) {
if (i == nums.length - 1) {
temp = nums[i];
break;
}
if (nums[i] == nums[i + 1]) {
i++;
} else {
temp = nums[i];
break;
}
}
return temp;
}
public static void heapSort(int[] sortArr) {
buildHeap(sortArr);
int n = sortArr.length - 1;
while (n > 0) {
int temp = sortArr[0]; //把根节点和最后一个元素交换
sortArr[0] = sortArr[n];
sortArr[n] = temp;
n--; // 交换之后,最后一个元素是最大的了,以后没必要在比较这个元素,所以n--
shiftDown(0, n, sortArr);
}
}
//自顶向下建堆,时间复杂度是O(nlog2n),空间复杂度是常数级别的,也没有达到不实用额外内存空间的要求
public static void buildHeap(int[] sortArr) {
for (int i = 1; i < sortArr.length; i++) {
shiftUp(i, sortArr);
}
}
//在插入的时候,一般都是插入到末尾,所以需要向上调 index 是插入数的索引
public static void shiftUp(int index, int[] sortArr) {
int parentIndex = (index - 1) / 2;
if (index > 0) {
if (sortArr[index] > sortArr[parentIndex]) {
int temp = sortArr[index];
sortArr[index] = sortArr[parentIndex];
sortArr[parentIndex] = temp;
shiftUp(parentIndex, sortArr);
}
}
}
//在删除根结点的时候,一般都是拿末尾的数来替换,所以需要向下调整 index 删除的节点的索引
public static void shiftDown(int index, int end, int[] sortArr) {
int sunLeft = 2 * index + 1; // 左孩子的索引
int sunRight = 2 * index + 2; // 右孩子的索引
//如果两个孩子都不是null
//堆的兄弟节点是无序的,所以需要比较出哪个节点更大,和更大的那个交换
if (sunLeft <= end && sunRight <= end) {
if (sortArr[sunLeft] >= sortArr[sunRight]) {
if (sortArr[index] < sortArr[sunLeft]) {
int temp = sortArr[index];
sortArr[index] = sortArr[sunLeft];
sortArr[sunLeft] = temp;
shiftDown(sunLeft, end, sortArr);
}
} else {
if (sortArr[index] < sortArr[sunRight]) {
int temp = sortArr[index];
sortArr[index] = sortArr[sunRight];
sortArr[sunRight] = temp;
shiftDown(sunRight, end, sortArr);
}
}
} else if (sunLeft <= end) {
if (sortArr[index] < sortArr[sunLeft]) {
int temp = sortArr[index];
sortArr[index] = sortArr[sunLeft];
sortArr[sunLeft] = temp;
shiftDown(sunLeft, end, sortArr);
}
}
}
看别人的答案,用位运算异或:
//注意:记住以后要求不能使用额外空间的时候,往位运算想想
//这里使用位异或运算 相同为 0 不同为 1 例如 4 ^ 1 = 0100 ^ 0001 = 0101
/**
* 交换律:a ^ b ^ c <=> a ^ c ^ b
* <p>
* 任何数于0异或为任何数 0 ^ n => n
* <p>
* 相同的数异或为0: n ^ n => 0
* <p>
* var a = [2,3,2,4,4]
* <p>
* 2 ^ 3 ^ 2 ^ 4 ^ 4等价于 2 ^ 2 ^ 4 ^ 4 ^ 3 => 0 ^ 0 ^3 => 3
*/
//注意:记住以后要求不能使用额外空间的时候,往位运算想想
//这里使用位异或运算 相同为 0 不同为 1 例如 4 ^ 1 = 0100 ^ 0001 = 0101
/**
* 交换律:a ^ b ^ c <=> a ^ c ^ b
* <p>
* 任何数于0异或为任何数 0 ^ n => n
* <p>
* 相同的数异或为0: n ^ n => 0
* <p>
* var a = [2,3,2,4,4]
* <p>
* 2 ^ 3 ^ 2 ^ 4 ^ 4等价于 2 ^ 2 ^ 4 ^ 4 ^ 3 => 0 ^ 0 ^3 => 3
*/
public int singleNumber(int[] nums) {
for (int i = 1; i < nums.length; i++) {
nums[0] = nums[i] ^ nums[0];
}
return nums[0];
}