从零开始的力扣(第二十六天)~
1.寻找旋转排序数组中的最小值 II
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请找出其中最小的元素。
注意数组中可能存在重复的元素。
示例 1:
输入: [1,3,5]
输出: 1
示例 2:
输入: [2,2,2,0,1]
输出: 0
说明:
这道题是 寻找旋转排序数组中的最小值 的延伸题目。
允许重复会影响算法的时间复杂度吗?会如何影响,为什么?
—————————————————————————————————————————
与之前不重复翻转那道题一样,只是在相等的时候不知道哪边有最小值,所以进行一次递归
class Solution:
def findMin(self, nums: List[int]) -> int:
n = len(nums)
first = 0
last = n - 1
while first < last:
mid = (first + last + 1) // 2
if nums[mid - 1] > nums[mid]:
return nums[mid]
elif nums[first] == nums[mid]:
a = self.findMin(nums[0:mid])
b = self.findMin(nums[mid:])
return a if a < b else b
elif nums[first] < nums[mid]:
first = mid
else:
last = mid
return nums[0]
2.寻找重复数
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入: [1,3,4,2,2]
输出: 2
示例 2:
输入: [3,1,3,4,2]
输出: 3
说明:
不能更改原数组(假设数组是只读的)。
只能使用额外的 O(1) 的空间。
时间复杂度小于 O(n2) 。
数组中只有一个重复的数字,但它可能不止重复出现一次。
—————————————————————————————————————————
首先想到先排序(不知道使用另一个列表保存排序结果,没有更改原数组算不算),然后遍历
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
li = sorted(nums)
for i in range(len(li) - 1):
if li[i] == li[i + 1]:
return li[i]
不过后来想了一下,sorted算法使用了O(n)的空间复杂度,不符合题意。
应该是唯一解法的快慢指针法,因为当有重复数时,一定在列表内有环(前一位数指向下一位地址)接下来就是找到哪两个数重复就行了
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
fast = 0
slow = 0;
while True:
fast = nums[nums[fast]]
slow = nums[slow]
if slow == fast:
fast = 0;
while nums[slow] != nums[fast]:
fast = nums[fast]
slow = nums[slow]
return nums[slow]
3.寻找两个有序数组的中位数
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
—————————————————————————————————————————
最开始想法是合并数组,因为时间复杂度要求O(log(m + n)),所以不能使用sorted,只能每一次在数组内去除两个数,直到得到最后一个或者两个数,算出中位数
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
li = nums1 + nums2
while len(li) > 2:
li.remove(max(li))
li.remove(min(li))
return sum(li) / len(li)
以为此方法使用了remove与max与min几个函数,时间复杂度超了,所以我更改了一下方式
直接在两个数组内分别删值,但是要考虑几种数组为空的情况
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
while (len(nums1) + len(nums2)) > 2:
if nums1 and nums2:
if nums1[0] <= nums2[0]:
nums1.pop(0)
else:
nums2.pop(0)
if nums1 and nums2:
if nums1[-1] >= nums2[-1]:
nums1.pop()
else:
nums2.pop()
elif nums1 == []:
nums2.pop()
else:
nums1.pop()
elif nums1 == []:
nums2.pop(0)
nums2.pop()
else:
nums1.pop(0)
nums1.pop()
return (sum(nums1) + sum(nums2)) / (len(nums1) + len(nums2))
但是其实这种方法中,pop函数当参数为0时,时间复杂度是O(n)的,所以还是不太好,但是基本达到了要求。
4.找出第 k 小的距离对
给定一个整数数组,返回所有数对之间的第 k 个最小距离。一对 (A, B) 的距离被定义为 A 和 B 之间的绝对差值。
示例 1:
输入:
nums = [1,3,1]
k = 1
输出:0
解释:
所有数对如下:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
因此第 1 个最小距离的数对是 (1,1),它们之间的距离为 0。
提示:
2 <= len(nums) <= 10000.
0 <= nums[i] < 1000000.
1 <= k <= len(nums) * (len(nums) - 1) / 2.
—————————————————————————————————————————
思路是二分法,因为距离的范围在0(可能距离最小值不是零)与数组内最大数值与最小数值之差中间,所以在这个范围内使用二分法找到第k个最小距离,判断条件是当原数组中距离小于mid的个数与k比较,这个数值大于k时,数组尾就要更改成mid,反之数组头更改成mid + 1
class Solution:
def smallestDistancePair(self, nums: List[int], k: int) -> int:
nums.sort()
n = len(nums)
first = 0
last = nums[-1] - nums[0]
while first < last:
mid = (first + last) // 2
i, count = 0, 0
for j in range(1, n):
while nums[j] - nums[i] > mid:
i += 1
count += j - i
if count < k:
first = mid + 1
else:
last = mid
return first
以上就是今日经验!