Skip to content

Commit 64cd7f6

Browse files
committed
136
1 parent 82a894d commit 64cd7f6

File tree

3 files changed

+126
-3
lines changed

3 files changed

+126
-3
lines changed

SUMMARY.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
* [98. Validate Binary Search Tree](leetCode-98-Validate-Binary-Search-Tree.md)
103103
* [99. Recover Binary Search Tree](leetcode-99-Recover-Binary-Search-Tree.md)
104104
* [100. Same Tree](leetcode-100-Same-Tree.md)
105-
* [101 题到 135](leetcode-101-200.md)
105+
* [101 题到 136](leetcode-101-200.md)
106106
* [101. Symmetric Tree](leetcode-101-Symmetric-Tree.md)
107107
* [102. Binary Tree Level Order Traversal](leetcode-102-Binary-Tree-Level-Order-Traversal.md)
108108
* [103. Binary Tree Zigzag Level Order Traversal](leetcode-103-Binary-Tree-Zigzag-Level-Order-Traversal.md)
@@ -137,4 +137,5 @@
137137
* [132. Palindrome Partitioning II](leetcode-132-Palindrome-PartitioningII.md)
138138
* [133. Clone Graph](leetcode-133-Clone-Graph.md)
139139
* [134. Gas Station](leetcode-134-Gas-Station.md)
140-
* [135. Candy](leetcode-135-Candy.md)
140+
* [135. Candy](leetcode-135-Candy.md)
141+
* [136. Single Number](leetcode-136-Single-Number.md)

leetcode-101-200.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,6 @@
6666

6767
<a href="leetcode-134-Gas-Station.html">134. Gas Station</a>
6868

69-
<a href="leetcode-135-Candy.html">135. Candy</a>
69+
<a href="leetcode-135-Candy.html">135. Candy</a>
70+
71+
<a href="leetcode-136-Single-Number.html">136. Single Number</a>

leetcode-136-Single-Number.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# 题目描述(简单难度)
2+
3+
![](https://windliang.oss-cn-beijing.aliyuncs.com/136.jpg)
4+
5+
所有数字都是成对出现的,只有一个数字是落单的,找出这个落单的数字。
6+
7+
# 解法一
8+
9+
题目要求线性复杂度内实现,并且要求没有额外空间。首先我们考虑假如没有空间复杂度的限制。
10+
11+
这其实就只需要统计每个数字出现的次数,很容易想到去用 `HashMap`
12+
13+
遍历一次数组,第一次遇到就将对应的 `key` 置为 `1`。第二次遇到就拿到 `key` 对应的 `value` 然后进行加 `1` 再存入。最后只需要寻找 `value``1``key` 就可以了。
14+
15+
利用 `HashMap` 统计字符个数已经用过很多次了,比如 [30 题](https://leetcode.wang/leetCode-30-Substring-with-Concatenation-of-All-Words.html)[49 题](https://leetcode.wang/leetCode-49-Group-Anagrams.html) 等等,最重要的好处就是可以在 `O(1)` 下取得之前的元素,从而使得题目的时间复杂度达到 `O(n)`
16+
17+
当然,注意到这个题目每个数字出现的次数要么是 `1` 次,要么是 `2` 次,所以我们也可以用一个 `HashSet` ,在第一次遇到就加到 `Set` 中,第二次遇到就把当前元素从 `Set` 中移除。这样遍历一遍后,`Set` 中剩下的元素就是我们要找的那个落单的元素了。
18+
19+
```java
20+
public int singleNumber(int[] nums) {
21+
HashSet<Integer> set = new HashSet<>();
22+
for (int i = 0; i < nums.length; i++) {
23+
if (!set.contains(nums[i])) {
24+
set.add(nums[i]);
25+
} else {
26+
set.remove(nums[i]);
27+
}
28+
}
29+
return set.iterator().next();
30+
}
31+
```
32+
33+
当然,上边的解法空间复杂度是 `O(n)`,怎么用 `O(1)` 的空间复杂度解决上边的问题呢?
34+
35+
想了很久,双指针,利用已确定元素的空间,等等的思想都考虑了,始终想不到解法,然后看了官方的 [Solution](https://leetcode.com/problems/single-number/solution/) ,下边分享一下。
36+
37+
# 解法二 数学推导
38+
39+
假设我们的数字是 `a b a b c c d`
40+
41+
怎么求出 `d` 呢?
42+
43+
只需要把出现过的数字加起来乘以 `2` ,然后减去之前的数字和就可以了。
44+
45+
什么意思呢?
46+
47+
上边的例子出现过的数字就是 `a b c d` ,加起来乘以二就是 `2 * ( a + b + c + d)`,之前的数字和就是 `a + b + a + b + c + c + d`
48+
49+
`2 * ( a + b + c + d) - (a + b + a + b + c + c + d)`,然后结果是不是就是 `d` 了。。。。。。
50+
51+
看完这个解法我只能说 `tql`。。。
52+
53+
找出现过什么数字,我们只需要一个 `Set` 去重就可以了。
54+
55+
```java
56+
public int singleNumber(int[] nums) {
57+
HashSet<Integer> set = new HashSet<>();
58+
int sum = 0;//之前的数字和
59+
for (int i = 0; i < nums.length; i++) {
60+
set.add(nums[i]);
61+
sum += nums[i];
62+
}
63+
int sumMul = 0;//出现过的数字和
64+
for (int n : set) {
65+
sumMul += n;
66+
}
67+
sumMul = sumMul * 2;
68+
return sumMul - sum;
69+
}
70+
```
71+
72+
上边的解法满足了题目要求,但还没有结束,下边的解法让我彻底跪了。
73+
74+
# 解法三 异或
75+
76+
还记得位操作中的异或吗?计算规则如下。
77+
78+
> 0 ⊕ 0 = 0
79+
>
80+
> 1 ⊕ 1 = 0
81+
>
82+
> 0 ⊕ 1 = 1
83+
>
84+
> 1 ⊕ 0 = 1
85+
86+
总结起来就是相同为零,不同为一。
87+
88+
根据上边的规则,可以推导出一些性质
89+
90+
* 0 ⊕ a = a
91+
* a ⊕ a = 0
92+
93+
此外异或满足交换律以及结合律。
94+
95+
所以对于之前的例子 `a b a b c c d` ,如果我们把给定的数字相互异或会发生什么呢?
96+
97+
```java
98+
a ⊕ b ⊕ a ⊕ b ⊕ c ⊕ c ⊕ d
99+
= ( a ⊕ a ) ⊕ ( b ⊕ b ) ⊕ ( c ⊕ c ) ⊕ d
100+
= 000 ⊕ d
101+
= d
102+
```
103+
104+
是的,答案就这样出来了,我妈妈问我为什么要跪着。。。
105+
106+
`java` 里的异或是 `^` 操作符,初始值可以给一个 `0`
107+
108+
```java
109+
public int singleNumber(int[] nums) {
110+
int ans = 0;
111+
for (int i = 0; i < nums.length; i++) {
112+
ans ^= nums[i];
113+
}
114+
return ans;
115+
}
116+
```
117+
118+
#
119+
120+
解法一利用 `HashMap` 计数算是一个很常用的思想了。解法二的数学推导理论上还能想到,解法三的异或操作真的是太神仙操作了,自愧不如。

0 commit comments

Comments
 (0)