Skip to content

Commit 699456f

Browse files
committed
go -> python
1 parent 3d98cb5 commit 699456f

File tree

1 file changed

+119
-116
lines changed

1 file changed

+119
-116
lines changed

data_structure/binary_op.md

Lines changed: 119 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -32,160 +32,163 @@ diff=(n&(n-1))^n
3232

3333
> 给定一个**非空**整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
3434
35-
```go
36-
func singleNumber(nums []int) int {
37-
// 10 ^10 == 00
38-
// 两个数异或就变成0
39-
result:=0
40-
for i:=0;i<len(nums);i++{
41-
result=result^nums[i]
42-
}
43-
return result
44-
}
35+
```Python
36+
class Solution:
37+
def singleNumber(self, nums: List[int]) -> int:
38+
39+
out = 0
40+
for num in nums:
41+
out ^= num
42+
43+
return out
4544
```
4645

4746
[single-number-ii](https://leetcode-cn.com/problems/single-number-ii/)
4847

4948
> 给定一个**非空**整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
5049
51-
```go
52-
func singleNumber(nums []int) int {
53-
// 统计每位1的个数
54-
var result int
55-
for i := 0; i < 64; i++ {
56-
sum := 0
57-
for j := 0; j < len(nums); j++ {
58-
// 统计1的个数
59-
sum += (nums[j] >> i) & 1
60-
}
61-
// 还原位00^10=10 或者用| 也可以
62-
result ^= (sum % 3) << i
63-
}
64-
return result
65-
}
50+
```Python
51+
class Solution:
52+
def singleNumber(self, nums: List[int]) -> int:
53+
seen_once = seen_twice = 0
54+
55+
for num in nums:
56+
seen_once = ~seen_twice & (seen_once ^ num)
57+
seen_twice = ~seen_once & (seen_twice ^ num)
58+
59+
return seen_once
6660
```
6761

6862
[single-number-iii](https://leetcode-cn.com/problems/single-number-iii/)
6963

7064
> 给定一个整数数组  `nums`,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
7165
72-
```go
73-
func singleNumber(nums []int) []int {
74-
// a=a^b
75-
// b=a^b
76-
// a=a^b
77-
// 关键点怎么把a^b分成两部分,方案:可以通过diff最后一个1区分
78-
79-
diff:=0
80-
for i:=0;i<len(nums);i++{
81-
diff^=nums[i]
82-
}
83-
result:=[]int{diff,diff}
84-
// 去掉末尾的1后异或diff就得到最后一个1的位置
85-
diff=(diff&(diff-1))^diff
86-
for i:=0;i<len(nums);i++{
87-
if diff&nums[i]==0{
88-
result[0]^=nums[i]
89-
}else{
90-
result[1]^=nums[i]
91-
}
92-
}
93-
return result
94-
}
66+
```Python
67+
class Solution:
68+
def singleNumber(self, nums: int) -> List[int]:
69+
# difference between two numbers (x and y) which were seen only once
70+
bitmask = 0
71+
for num in nums:
72+
bitmask ^= num
73+
74+
# rightmost 1-bit diff between x and y
75+
diff = bitmask & (-bitmask)
76+
77+
x = 0
78+
for num in nums:
79+
# bitmask which will contain only x
80+
if num & diff:
81+
x ^= num
82+
83+
return [x, bitmask^x]
9584
```
9685

9786
[number-of-1-bits](https://leetcode-cn.com/problems/number-of-1-bits/)
9887

9988
> 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’  的个数(也被称为[汉明重量](https://baike.baidu.com/item/%E6%B1%89%E6%98%8E%E9%87%8D%E9%87%8F))。
10089
101-
```go
102-
func hammingWeight(num uint32) int {
103-
res:=0
104-
for num!=0{
105-
num=num&(num-1)
106-
res++
107-
}
108-
return res
109-
}
90+
```Python
91+
class Solution:
92+
def hammingWeight(self, n: int) -> int:
93+
num_ones = 0
94+
while n > 0:
95+
num_ones += 1
96+
n &= n - 1
97+
return num_ones
11098
```
11199

112100
[counting-bits](https://leetcode-cn.com/problems/counting-bits/)
113101

114102
> 给定一个非负整数  **num**。对于  0 ≤ i ≤ num  范围中的每个数字  i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
115103
116-
```go
117-
func countBits(num int) []int {
118-
res:=make([]int,num+1)
119-
120-
for i:=0;i<=num;i++{
121-
res[i]=count1(i)
122-
}
123-
return res
124-
}
125-
func count1(n int)(res int){
126-
for n!=0{
127-
n=n&(n-1)
128-
res++
129-
}
130-
return
131-
}
104+
思路:利用上一题的解法容易想到 O(nk) 的解法,k 为位数。但是实际上可以利用动态规划将复杂度降到 O(n),想法其实也很简单,即当前数的 1 个数等于比它少一个 1 的数的结果加 1。下面给出三种 DP 解法
105+
106+
```Python
107+
# x <- x // 2
108+
class Solution:
109+
def countBits(self, num: int) -> List[int]:
110+
111+
num_ones = [0] * (num + 1)
112+
113+
for i in range(1, num + 1):
114+
num_ones[i] = num_ones[i >> 1] + (i & 1) # 注意位运算的优先级
115+
116+
return num_ones
117+
```
118+
119+
```Python
120+
# x <- x minus right most 1
121+
class Solution:
122+
def countBits(self, num: int) -> List[int]:
123+
124+
num_ones = [0] * (num + 1)
125+
126+
for i in range(1, num + 1):
127+
num_ones[i] = num_ones[i & (i - 1)] + 1
128+
129+
return num_ones
132130
```
133131

134-
另外一种动态规划解法
135-
136-
```go
137-
func countBits(num int) []int {
138-
res:=make([]int,num+1)
139-
for i:=1;i<=num;i++{
140-
// 上一个缺1的元素+1即可
141-
res[i]=res[i&(i-1)]+1
142-
}
143-
return res
144-
}
132+
```Python
133+
# x <- x minus left most 1
134+
class Solution:
135+
def countBits(self, num: int) -> List[int]:
136+
137+
num_ones = [0] * (num + 1)
138+
139+
left_most = 1
140+
141+
while left_most <= num:
142+
for i in range(left_most):
143+
if i + left_most > num:
144+
break
145+
num_ones[i + left_most] = num_ones[i] + 1
146+
left_most <<= 1
147+
148+
return num_ones
145149
```
146150

147151
[reverse-bits](https://leetcode-cn.com/problems/reverse-bits/)
148152

149153
> 颠倒给定的 32 位无符号整数的二进制位。
150154
151-
思路:依次颠倒即可
152-
153-
```go
154-
func reverseBits(num uint32) uint32 {
155-
var res uint32
156-
var pow int=31
157-
for num!=0{
158-
// 把最后一位取出来,左移之后累加到结果中
159-
res+=(num&1)<<pow
160-
num>>=1
161-
pow--
162-
}
163-
return res
164-
}
155+
思路:简单想法依次颠倒即可。更高级的想法是考虑到处理超长比特串时可能出现重复的pattern,此时如果使用 cache 记录出现过的 pattern 并在重复出现时直接调用结果可以节约时间复杂度,具体可以参考 leetcode 给出的解法。
156+
157+
```Python
158+
import functools
159+
160+
class Solution:
161+
def reverseBits(self, n):
162+
ret, power = 0, 24
163+
while n:
164+
ret += self.reverseByte(n & 0xff) << power
165+
n = n >> 8
166+
power -= 8
167+
return ret
168+
169+
# memoization with decorator
170+
@functools.lru_cache(maxsize=256)
171+
def reverseByte(self, byte):
172+
return (byte * 0x0202020202 & 0x010884422010) % 1023
165173
```
166174

167175
[bitwise-and-of-numbers-range](https://leetcode-cn.com/problems/bitwise-and-of-numbers-range/)
168176

169177
> 给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。
170178
171-
```go
172-
func rangeBitwiseAnd(m int, n int) int {
173-
// m 5 1 0 1
174-
// 6 1 1 0
175-
// n 7 1 1 1
176-
// 把可能包含0的全部右移变成
177-
// m 5 1 0 0
178-
// 6 1 0 0
179-
// n 7 1 0 0
180-
// 所以最后结果就是m<<count
181-
var count int
182-
for m!=n{
183-
m>>=1
184-
n>>=1
185-
count++
186-
}
187-
return m<<count
188-
}
179+
思路:直接从 m 到 n 遍历一遍显然不是最优。一个性质,如果 m 不等于 n,则结果第一位一定是 0 (中间必定包含一个偶数)。利用这个性质,类似的将 m 和 n 右移后我们也可以判断第三位、第四位等等,免去了遍历的时间复杂度。
180+
181+
```Python
182+
class Solution:
183+
def rangeBitwiseAnd(self, m: int, n: int) -> int:
184+
185+
shift = 0
186+
while m < n:
187+
shift += 1
188+
m >>= 1
189+
n >>= 1
190+
191+
return m << shift
189192
```
190193

191194
## 练习

0 commit comments

Comments
 (0)