《剑指offer》python实现系列,全目录
题目一
在一个长度为 n 的数组里的所有数字都在 0~m-1 的范围内。数组中某
些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了
几次。请找出数组中任意一个重复的数字。例如,如果输入长度为 7 的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字 2 或者 3。
最初想法
最简单的方法是遍历数组,
优化:创建一个长度为n的辅助数组temp,读取原数组值x,令temp[x]=1,再读入新元素检测是否为1即可。
使用辅助数组
1
2
3
4
5
6
7
8
9def duplicate( numbers, duplication):
temp = [0]*len(numbers)
for i in numbers:
if temp[i] == 1:
duplication[0] = i
return True
temp[i] = 1
return False
不使用辅助数组:【官方】
直接在原数组上交换元素,确保元素与其下标相等。
详细思路:看书上的例子p39
1
2
3
4
5
6
7
8
9def duplicate( numbers, duplication):
for i in range(len(numbers)):
while i != numbers[i]:#保证元素与下标i对应
if numbers[numbers[i]] == numbers[i]: #如果已经有元素
duplication[0] = numbers[i]
return True
else:
numbers[numbers[i]], numbers[i] = numbers[i], numbers[numbers[i]] #交换位置
return False
我的方法
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14#还是利用下标,将nums[i]位置的元素乘以-1
class Solution(object):
def findRepeatNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
for i in range(len(nums)):
temp = abs(nums[i])
if nums[temp] < 0:
return temp
else:
nums[temp] = -nums[temp]
return 0#如果到底也没return,那一定是0乘-1了
题目二
不修改数组,不利于辅助空间,找出重复数字
在一个长度为 n+1 的数组里的所有数字都在 1~ n 的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,如果输入长度为 8 的数组(2,3,5,4,3,2,67), 那么对应的输出是重复的数字 2 或者 3
利用二分查找
我们以长度为 8 的数组{2,3,5,4,3,2,6,7}为例分析查找的过程。根据题目要求,这个长度为 8 的所有数字都在 17 的范围内。中间的数字 4 把 17 的范围分为两段,一段是 14, 另一段是 57。接下来我们统计 1 -4 这 4 个数字在数组中出现的次数,它们一共出现了 5 次,因此这 4 个数字中一定有重复的数字。
接下来我们再把 1~4 的范围一分为二,一段是 1、2 两个数字,另一段是 3、4 两个数字。数字 1 或者 2 在数组中一共出现了两次。我们再统计数字 3 或者 4 在数组中出现的次数,它们一共出现了三次。这意味着 3、4 两个数字中一定有一个重复了。我们再分别统计这两个数字在数组中出现的次数。接着我们发现数字 3 出现了两次,是一个重复的数字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class Solution(object):
def findRepeatNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
start =1
end = n-1
while start<=end:
mid = (start+end)//2
count = 0
for elem in nums:
if start <= elem <= mid:
count += 1
if end == start:
if count >1:
return start
if count > (mid-start)+1:#重复元素在【start与mid区间】
end = mid
else:
start = mid+1
return mid