Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Miykael_xxm
leetcode
提交
839b652f
L
leetcode
项目概览
Miykael_xxm
/
leetcode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
L
leetcode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
839b652f
编写于
3月 24, 2020
作者:
L
lucifer
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 位运算
上级
0794b646
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
201 addition
and
3 deletion
+201
-3
README.md
README.md
+4
-3
thinkings/bit.md
thinkings/bit.md
+197
-0
未找到文件。
README.md
浏览文件 @
839b652f
...
...
@@ -281,11 +281,12 @@ leetcode 题解,记录自己的 leetcode 解题之路。
-
[
布隆过滤器
](
./thinkings/bloom-filter.md
)
-
[
字符串问题
](
./thinkings/string-problems.md
)
-
[
前缀树专题
](
./thinkings/trie.md
)
-
[
《日程安排》专题
](
https://lucifer.ren/blog/2020/02/03/leetcode-%E6%88%91%E7%9A%84%E6%97%A5%E7%A8%8B%E5%AE%89%E6%8E%92%E8%A1%A8%E7%B3%BB%E5%88%97/
)
🆕
-
[
《构造二叉树》专题
](
https://lucifer.ren/blog/2020/02/08/%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%93%E9%A2%98/
)
🆕
-
[
《日程安排》专题
](
https://lucifer.ren/blog/2020/02/03/leetcode-%E6%88%91%E7%9A%84%E6%97%A5%E7%A8%8B%E5%AE%89%E6%8E%92%E8%A1%A8%E7%B3%BB%E5%88%97/
)
-
[
《构造二叉树》专题
](
https://lucifer.ren/blog/2020/02/08/%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%93%E9%A2%98/
)
-
[
《贪婪策略》专题
](
./thinkings/greedy.md
)
🆕
-
[
《深度优先遍历》专题
](
./thinkings/DFS.md
)
🆕
-
[
滑动窗口(思路 + 模板)
](
./thinkings/slide-window.md
)
-
[
滑动窗口(思路 + 模板)
](
./thinkings/slide-window.md
)
🆕
-
[
位运算
](
./thinkings/bit.md
)
🆕
### anki 卡片
...
...
thinkings/bit.md
0 → 100644
浏览文件 @
839b652f
# 位运算
我这里总结了几道位运算的题目分享给大家,分别是 136和137, 260 和 645, 总共加起来四道题。 四道题全部都是位运算的套路,如果你想练习位运算的话,不要错过哦~~
## 前菜
开始之前我们先了解下异或,后面会用到。
1.
异或的性质
两个数字异或的结果
`a^b`
是将 a 和 b 的二进制每一位进行运算,得出的数字。 运算的逻辑是果同一位的数字相同则为 0,不同则为 1
2.
异或的规律
-
任何数和本身异或则为
`0`
-
任何数和 0 异或是
`本身`
3.
异或运算满足交换律,即:
`a ^ b ^ c = a ^ c ^ b`
OK,我们来看下这三道题吧。
## 136. 只出现一次的数字1
题目大意是除了一个数字出现一次,其他都出现了两次,让我们找到出现一次的数。我们执行一次全员异或即可。
```
python
class
Solution
:
def
singleNumber
(
self
,
nums
:
List
[
int
])
->
int
:
single_number
=
0
for
num
in
nums
:
single_number
^=
num
return
single_number
```
***复杂度分析**
*
-
时间复杂度:$O(N)$,其中N为数组长度。
-
空间复杂度:$O(1)$
## 137. 只出现一次的数字2
题目大意是除了一个数字出现一次,其他都出现了三次,让我们找到出现一次的数。 灵活运用位运算是本题的关键。
Python3:
```
python
class
Solution
:
def
singleNumber
(
self
,
nums
:
List
[
int
])
->
int
:
res
=
0
for
i
in
range
(
32
):
cnt
=
0
# 记录当前 bit 有多少个1
bit
=
1
<<
i
# 记录当前要操作的 bit
for
num
in
nums
:
if
num
&
bit
!=
0
:
cnt
+=
1
if
cnt
%
3
!=
0
:
# 不等于0说明唯一出现的数字在这个 bit 上是1
res
|=
bit
return
res
-
2
**
32
if
res
>
2
**
31
-
1
else
res
```
-
为什么Python最后需要对返回值进行判断?
如果不这么做的话测试用例是[-2,-2,1,1,-3,1,-3,-3,-4,-2] 的时候,就会输出 4294967292。 其原因在于Python是动态类型语言,在这种情况下其会将符号位置的1看成了值,而不是当作符号“负数”。 这是不对的。 正确答案应该是 - 4,-4的二进制码是 1111...100,就变成 2^32-4=4294967292,解决办法就是 减去 2
**
32 。
> 之所以这样不会有问题的原因还在于题目限定的数组范围不会超过 2 ** 32
JavaScript:
```
js
var
singleNumber
=
function
(
nums
)
{
let
res
=
0
;
for
(
let
i
=
0
;
i
<
32
;
i
++
)
{
let
cnt
=
0
;
let
bit
=
1
<<
i
;
for
(
let
j
=
0
;
j
<
nums
.
length
;
j
++
)
{
if
(
nums
[
j
]
&
bit
)
cnt
++
;
}
if
(
cnt
%
3
!=
0
)
res
=
res
|
bit
;
}
return
res
;
};
```
***复杂度分析**
*
-
时间复杂度:$O(N)$,其中N为数组长度。
-
空间复杂度:$O(1)$
## 645. 错误的集合
和上面的
`137. 只出现一次的数字2`
思路一样。这题没有限制空间复杂度,因此直接hashmap 存储一下没问题。 不多说了,我们来看一种空间复杂度$O(1)$的解法。
由于和
`137. 只出现一次的数字2`
思路基本一样,我直接复用了代码。具体思路是,将nums的所有索引提取出一个数组idx,那么由idx和nums组成的数组构成singleNumbers的输入,其输出是唯二不同的两个数。
但是我们不知道哪个是缺失的,哪个是重复的,因此我们需要重新进行一次遍历,判断出哪个是缺失的,哪个是重复的。
```
python
class
Solution
:
def
singleNumbers
(
self
,
nums
:
List
[
int
])
->
List
[
int
]:
ret
=
0
# 所有数字异或的结果
a
=
0
b
=
0
for
n
in
nums
:
ret
^=
n
# 找到第一位不是0的
h
=
1
while
(
ret
&
h
==
0
):
h
<<=
1
for
n
in
nums
:
# 根据该位是否为0将其分为两组
if
(
h
&
n
==
0
):
a
^=
n
else
:
b
^=
n
return
[
a
,
b
]
def
findErrorNums
(
self
,
nums
:
List
[
int
])
->
List
[
int
]:
nums
=
[
0
]
+
nums
idx
=
[]
for
i
in
range
(
len
(
nums
)):
idx
.
append
(
i
)
a
,
b
=
self
.
singleNumbers
(
nums
+
idx
)
for
num
in
nums
:
if
a
==
num
:
return
[
a
,
b
]
return
[
b
,
a
]
```
***复杂度分析**
*
-
时间复杂度:$O(N)$
-
空间复杂度:$O(1)$
## 260. 只出现一次的数字3
题目大意是除了两个数字出现一次,其他都出现了两次,让我们找到这个两个数。
我们进行一次全员异或操作,得到的结果就是那两个只出现一次的不同的数字的异或结果。
我们刚才讲了异或的规律中有一个
`任何数和本身异或则为0`
, 因此我们的思路是能不能将这两个不同的数字分成两组 A 和 B。
分组需要满足两个条件.
1.
两个独特的的数字分成不同组
2.
相同的数字分成相同组
这样每一组的数据进行异或即可得到那两个数字。
问题的关键点是我们怎么进行分组呢?
由于异或的性质是,同一位相同则为 0,不同则为 1. 我们将所有数字异或的结果一定不是 0,也就是说至少有一位是 1.
我们随便取一个, 分组的依据就来了, 就是你取的那一位是 0 分成 1 组,那一位是 1 的分成一组。
这样肯定能保证
`2. 相同的数字分成相同组`
, 不同的数字会被分成不同组么。 很明显当然可以, 因此我们选择是 1,也就是
说
`两个独特的的数字`
在那一位一定是不同的,因此两个独特元素一定会被分成不同组。
```
python
class
Solution
:
def
singleNumbers
(
self
,
nums
:
List
[
int
])
->
List
[
int
]:
ret
=
0
# 所有数字异或的结果
a
=
0
b
=
0
for
n
in
nums
:
ret
^=
n
# 找到第一位不是0的
h
=
1
while
(
ret
&
h
==
0
):
h
<<=
1
for
n
in
nums
:
# 根据该位是否为0将其分为两组
if
(
h
&
n
==
0
):
a
^=
n
else
:
b
^=
n
return
[
a
,
b
]
```
***复杂度分析**
*
-
时间复杂度:$O(N)$,其中N为数组长度。
-
空间复杂度:$O(1)$
更多题解可以访问我的LeetCode题解仓库:https://github.com/azl397985856/leetcode 。 目前已经接近30K star啦。
大家也可以关注我的公众号《脑洞前端》获取更多更新鲜的LeetCode题解
![](
https://pic.leetcode-cn.com/89ef69abbf02a2957838499a96ce3fbb26830aae52e3ab90392e328c2670cddc-file_1581478989502
)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录