两数之和 BM50
原题
给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。
(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)
数据范围:
2
≤
l
e
n
(
n
u
m
b
e
r
s
)
≤
1
0
5
,
?
10
≤
n
u
m
b
e
r
s
i
≤
1
0
9
,
0
≤
t
a
r
g
e
t
≤
1
0
9
2\leq len(numbers) \leq 10^5,-10 \leq numbers_i \leq 10^9,0 \leq target \leq 10^9
2≤len(numbers)≤105,?10≤numbersi?≤109,0≤target≤109
要求:空间复杂度
O
(
n
)
O(n)
O(n),时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
思路:
使用哈希表来降低时间复杂度,遍历数组,如果没有 当前值, 就将(target - 当前值)存入哈希表,如果有,返回数字下标即可。
class Solution:
def twoSum(self , numbers: List[int], target: int) -> List[int]:
# write code here
d = {}
for k in range(len(numbers)):
if numbers[k] not in d:
d[target - numbers[k]] = k+1
else:
return [d[numbers[k]],k+1]
数组中出现次数超过一半的数字 BM51
原题
描述
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
数据范围:
n
≤
50
n \le 50
n≤50,数组中元素的值
0
≤
v
a
l
≤
100000
0 \le val \le 100000
0≤val≤100000
要求:空间复杂度:
O
(
1
)
O(1)
O(1),时间复杂度
O
(
n
)
O(n)
O(n)
输入描述:
保证数组输入非空,且保证有解
思路1:
使用哈希表存储每个元素出现的次数,如果超过一半,直接返回该元素.
时间复杂度:O(n),空间复杂度:O(n)
class Solution:
def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
# write code here
d = {}
for k in numbers:
if k not in d:
d[k] = 1
else:
d[k] += 1
if d[k] > len(numbers)//2:
return k
思路2:投票法
出现次数超过一半,那该数字一定是众数,对数组中的数字进行相消,即如果两个数不相等,就消去这两个数,最坏情况下,每次消去一个众数和一个非众数,那么如果存在众数,最后留下的数肯定是众数。
时间复杂度:O(n),空间复杂度:O(1)
- a表示众数出现的次数,res存储众数。
- 如果a=0,说明前面的数字抵消了,因此假设当前的数字为众数,
r
e
s
=
k
res=k
res=k
- 如果当前数字和res相等,则令a加1;否则令a减一,表示抵消
class Solution:
def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
# write code here
a = 0
for k in numbers:
if a == 0:
res = k
if res == k:
a += 1
else:
a -= 1
return res
数组中只出现一次的两个数字 BM52
原题
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
数据范围:数组长度
2
≤
n
≤
1000
2\le n \le 1000
2≤n≤1000,数组中每个数的大小
0
<
v
a
l
≤
1000000
0 < val \le 1000000
0<val≤1000000 要求:空间复杂度
O
(
1
)
O(1)
O(1),时间复杂度
O
(
n
)
O(n)
O(n)。提示:输出时按非降序排列。
思路1:
哈希表存储每个数字出现的次数;遍历哈希表,找到只出现一次的数字
class Solution:
def FindNumsAppearOnce(self , array: List[int]) -> List[int]:
# write code here
dic = {}
lst = []
for i in array:
if i not in dic:
dic[i] = 1
else:
dic[i] += 1
for k in dic:
if dic[k] < 2:
lst.append(k)
return sorted(lst)
思路2:
异或,数组中只出现一次的数字,对数组所有元素进行异或运算,即可得到只出现一次的数字。因此解决两个只出现一次的数字,只需要将数组分为两组,两个只出现一次的数字分别分布在两组中,对两组分别进行异或运算,即可得到结果。
难点在于,如何进行分组,可以使两个元素刚好分布在两个不同的分组里。
假设要找到的两个元素为a、b,首先计算所有元素的异或,假设异或结果存储在xor中。若xor的第i位等于1,说明a和b的第i位一个是1一个是0。因此可以找到xor中的最低位1,根据最低位为0或1将原始数组分为两组即可。
- 首先计算所有元素的异或结果,xor
- 计算xor的最低位1,即令
l
o
w
=
1
low=1
low=1,如果low&上xor等于0,说明第一位不是1,则low左移,直到low&上xor等于1,找到xor的最低位1。为了便于后续理解,假设我们找到的最低位为low_bit
- 元素分组,如果当前元素与上low等于0,说明该元素的第low_bit位为0;否则该元素的第low_bit位为1。这样数组元素就分为了两组,分别用a和b存储两组元素的异或结果,最终a和b即为要求的两个只出现一次的元素
class Solution:
def FindNumsAppearOnce(self , array: List[int]) -> List[int]:
# write code here
xor = 0
for k in array:
xor ^= k
low = 1
while not low & xor:
low <<= 1
a ,b = 0,0
for k in array:
if low & k == 0:
a ^= k
else:
b ^= k
if a > b:
a,b = b,a
return [a,b]
缺失的第一个正整数 BM53
原题
给定一个未排序的整数数组nums,请你找出其中没有出现的最小的正整数 。进阶: 空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
数据范围:
?
2
31
<
=
n
u
m
s
[
i
]
<
=
2
31
?
1
-2^{31}<=nums[i]<=2^{31}-1
?231<=nums[i]<=231?1
0
<
=
l
e
n
(
n
u
m
s
)
<
=
5
?
1
0
5
0<=len(nums)<=5*10^5
0<=len(nums)<=5?105
思路1:
使用哈希表记录nums中每个元素出现的位置,定义一个num初始化为1,当num出现在nums中,则num加1,直到nums中不存在num,直接返回num。使用哈希表存储nums中的元素,便于后续进行O(1)的查找。
class Solution:
def minNumberDisappeared(self , nums: List[int]) -> int:
# write code here
d = {}
for i in range(len(nums)):
d[nums[i]] = i
num = 1
while True:
if num in d:
num += 1
else:
return num
思路2:
原地哈希,一共有n个元素,则定义一个长度为n的数组,记录1-n范围内数字的出现情况。该题最终返回的要么是1-n之间的数字,要么是n+1
三数之和 BM54
原题
给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。
数据范围:$0 \le n \le $,数组中各个元素值满足
∣
v
a
l
∣
≤
100
|val | \le 100
∣val∣≤100。空间复杂度:O(n^2)O(n2),时间复杂度 O(n^2)O(n2)
注意:
- 三元组(a、b、c)中的元素可以按任意顺序排列。
- 解集中不能包含重复的三元组。
思路:
使用一个哈希表记录num中每个元素出现的位置,为了后面进行O(1)的查找
步骤:双重循环遍历num,i从0—(n-1),j从(i+1)—(n-1),计算num[i]+num[j],查找哈希表中是否存在-(num[i]+num[j]),如果存在,且该元素与num[i]和num[j]不冲突,则证明这是一个有效的三元组。
注意事项:为了避免获取到重复的结果,需要进行去重,因此先对num数组进行排序,则num[i]一定小于num[j],保证每个三元组都是有序的,因而可以直接判断当前三元组是否已经在结果集中,如果在,过滤。
class Solution:
def threeSum(self , num: List[int]) -> List[List[int]]:
res = []
d = {}
num = sorted(num)
for k in range(len(num)):
d[num[k]] = k
for i in range(len(num)):
for j in range(i+1,len(num)):
t = -(num[i] + num[j])
if t in d and d[t] != i and d[t] != j:
if t < num[i]:
r = [t,num[i],num[j]]
elif t > num[j]:
r= [num[i],num[j],t]
else:
r = [num[i],t,num[j]]
if r not in res:
res.append(r)
return res
|