第5天
1.剑指Offer45.把数组排成最小的数
描述:给定一个非负整数数组 nums。
要求:将数组中的数字拼接起来排成一个数,打印能拼接出的所有数字中的最小的一个。
class Solution:
def minNumber(self, nums: List[int]) -> str:
n = len(nums)
if n ==0:
return ""
for i in range(n):
nums[i] = str(nums[i])
for i in range(n):
for j in range(i+1,n):
if nums[i] + nums[j] > nums[j]+nums[i]:
nums[i],nums[j] = nums[j],nums[i]
return "".join(nums)
反思:在做这一道题时,思路不是很清晰,也不知该如何下手进行编程,于是就浏览了一些题解。这个方法是,先把数组中的每个元素转成字符串的形式,在进行拼接,若是nums[i] + nums[j] > nums[j]+nums[i],那么说明当前的排序并不是最小的,则需要交换,使排序最小。
2.0283.移动零
描述:给定一个数组 nums。
要求:将所有 0 移动到末尾,并保持原有的非 0 数字的相对顺序。
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
for i in nums:
if i == 0 :
index_1 = nums.index(i)
del nums[index_1]
nums.append(0)
else: continue
return nums
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
i=0
j=0
for i in range(len(nums)):
if nums[i]!=0:
nums[j] , nums[i] = nums[i],nums[j]
j+=1
反思:上两段代码分别是笔者第一次编写,与第二次浏览题解后所选用的方法;
第一种:参考了之前数组的左移右移的方法,先找到列表中的 ‘0’ ,并记录下它的下标。然后运用函数del,删除掉该下标处的 ‘0’ ,最后在数组最后添加上一个 ‘0’ 即可。但是可以看出,该方法所消耗的时间很多。
第二种:这种方法也比较巧妙,它是在数组中遍历,如果第一次找到了非0的元素,则让该元素与数组第一位进行交换,如果第二次碰到非0的元素,则与数组的第二位进行交换。这样看似是非零元素的交换,实际上是元素 0 向后进行了移动。
3.0912.移动数组
描述:给定一个整数数组 nums。
要求:将该数组升序排列。
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
return sorted(nums)
反思:这一题,是第一个“秒杀”题,要是平时都可以秒杀就好了。(*^_^*)
第6天
1.0506.相对名次
描述:给定一个长度为 n 的数组score。其中score[i] 表示第i名运动员在比赛中的成绩。所有成绩互不相同。
要求:找出他们的相对名次,并授予前三名对应的奖牌。前三名运动员将会被分别授予「金牌("Gold Medal"
)」,「银牌("Silver Medal"
)」和「铜牌("Bronze Medal"
)」。
class Solution:
def findRelativeRanks(self, score: List[int]) -> List[str]:
scoreDict = {}
for i in score :
scoreDict[i] = 0
a = sorted(score)
a.sort(reverse = True)
if len(score) >= 1:
scoreDict[a[0]] = 'Gold Medal'
if len(score) >= 2:
scoreDict[a[1]] = 'Silver Medal'
if len(score) >= 3:
scoreDict[a[2]] = 'Bronze Medal'
if len (score) >= 4:
j = 4
for i in a[3:]:
scoreDict[i] = str(j)
j +=1
i =0
for i in range(len(score)):
score[i]= scoreDict[score[i]]
return score
反思:在进行这道题的思考时,我也想到了使用字典的键值对的关系,来表示名次与对应的元素的关系,但是对于如何填入字典与如何按原数组的顺序输出,这两个问题在脑袋中还是一团糊。于是,我就到题解处寻找到了一个也是运用字典的算法。在学习完之后,解题思路有了一种不一样的变化,感到收获很多。
2.0088合并两个有序数组
描述:给定两个有序数组 nums1、nums2。
要求:将 nums2合并到 nums1中,使nums1成为一个有序数组。
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
k = m + n - 1
while m > 0 and n > 0:
if nums1[m-1]>nums2[n-1]:
nums1[k]= nums1[m-1]
m-=1
else:
nums1[k] = nums2[n-1]
n-=1
k-=1
nums1[:n]=nums2[:n]
反思:在拿到这道题时,我原本打算使用学到的归并排序算法进行解答,可是,在num1的最后总是输不对数字,于是我就去浏览了大佬们的想法。这个方法,是从后往前比较,最后,若是nums2的前n项还有剩余,那么就将其剪切到nums1的前n项去。相比于我之前写的代码,是相当的简洁了,而且从后往前的比较也很新颖。
3.剑指Offer51.数组中的逆序对
描述:给定一个数组 nums。
要求:计算出数组中的逆序对的总数。
class Solution:
def reversePairs(self, nums: List[int]) -> int:
def merge_sort(l, r):
if l >= r: return 0
m = (l + r) // 2
res = merge_sort(l, m) + merge_sort(m + 1, r)
i, j = l, m + 1
tmp[l:r + 1] = nums[l:r + 1]
for k in range(l, r + 1):
if i == m + 1:
nums[k] = tmp[j]
j += 1
elif j == r + 1 or tmp[i] <= tmp[j]:
nums[k] = tmp[i]
i += 1
else:
nums[k] = tmp[j]
j += 1
res += m - i + 1
return res
tmp = [0] * len(nums)
return merge_sort(0, len(nums) - 1)
反思: 一开始解决这时我本来想是从数组中的第一个元素开始进行遍历,然后再逐一的统计逆序数的个数。但是最后的结果却是超出了时间限制,苦想一番后也没得到一个好的方法。于是便去看看大佬怎么做的。这个方法是归并排序的变式,在归并排序的最后排序时,需要两个子数组进行比较填入,此时若是左边的数组比右边的大,那么就可以进行逆序对的增加。想通了之后,我恍然大悟,原来可以这么解决。
第7天
1.0075.颜色分类
描述:给定一个数组nums,元素值只有 0、1、2,分别代表红色、白色、蓝色。
要求:将数组进行排序,使得红色在前,白色在中间,蓝色在最后。
class Solution:
def sortColors(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
p0, curr, p2 = 0, 0, len(nums) - 1
while curr <= p2:
if nums[curr] == 0:
nums[p0], nums[curr] = nums[curr], nums[p0]
p0 += 1
curr += 1
elif nums[curr] == 2:
nums[p2], nums[curr] = nums[curr], nums[p2]
p2 -= 1
else:
curr += 1
反思: 一开始看到这道题,我就直接使用了sort()函数直接解决,却没看到不能使用。然后,就借鉴了一下一些题解。这个方法是通过三个指针(p0,curr,p2)在列表中进行遍历和交换,将0和2分别移到列表的两端,1留在中间,很巧妙的解决了问题。
2.0215.数组中的第K个最大元素
描述:给定一个未排序的整数数组nums和一个整数k。
要求:返回数组中第k个最大的元素。
##方法一
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
nums.sort()
return nums[-k]
反思: 这是我在写这题时第一次使用的方法,使用了内置函数sort(),有点取巧了,虽然能成功解决问题,但是时间复杂度并不是O(n),而是O(n log n),因此我也很苦恼:如何才能优化代码,变成O(n)的程序。
class Solution:
def findKthLargest(self, nums, k):
def quick_select(nums, k):
pivot = random.choice(nums)
big, equal, small = [], [], []
for num in nums:
if num > pivot:
big.append(num)
elif num < pivot:
small.append(num)
else:
equal.append(num)
if k <= len(big):
return quick_select(big, k)
if len(nums) - len(small) < k:
return quick_select(small, k - len(nums) + len(small))
return pivot
return quick_select(nums, k)
反思: 这是我在题解里找到的一种时间复杂度是O(n)的算法,它是运用了快速排序并递归的方式解决问题。学习了这个算法后,我感觉对快速排序的认知又更清晰了一些。
3.剑指Offer40。最小的K个数
描述:给定整数数组 arr,再给定一个整数k。
要求:返回数组arr中最小的k个数。
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
arr.sort()
i=0
count=[]
while i < k :
count.append(arr[i])
i += 1
return count
反思: 这题我的想法是,先用内置函数sort()使数组内进行排序,然后在建立一个空数组储存需要输出的第K个数。因为便捷就使用了sort()函数。
第8天
1.1122.数组的相对排序
描述:给定两个数组,arr1和arr2,其中arr2 中的元素各不相同,arr2中的每个元素都出现在 arr1中。
要求:对arr1 中的元素进行排序,使arr1 中项的相对顺序和arr2中的相对顺序相同。未在arr2 中出现过的元素需要按照升序放在arr1 的末尾。
class Solution:
def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
n = len(arr1)
res = []
for i in arr2:
count = arr1.count(i)
while count != 0:
res.append(i)
count -= 1
arr1.remove(i)
res = res + sorted(arr1)
return res
反思:一开始做这道题时,我本来想使用插入排序,让 arr1 中的每个元素都插入到 arr2 中的对应位置,剩下的元素则使用sort()函数排序后在进行添加,可是程序一直出错。于是我就到题解里寻找一种方法。这个方法我觉得和我的想法有类似的地方,它先是记录了arr2中的各元素的数目,再用添加到一个新建立的数组里,因为arr2中的元素在arr1中都有出现,因此,最后只需要把arr1中对应的元素删除,并添加上剩下的部分就可以解决。
2.0220.存在重复元素Ⅲ
给你一个整数数组 nums
和两个整数 indexDiff
和 valueDiff
。
找出满足下述条件的下标对 (i, j)
:
i != j
,abs(i - j) <= indexDiff
abs(nums[i] - nums[j]) <= valueDiff
如果存在,返回 true
;否则,返回 false
。
class Solution:
def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
if t < 0 or k < 0:
return False
all_buckets = {}
bucket_size = t + 1
for i in range(len(nums)):
bucket_num = nums[i] // bucket_size
if bucket_num in all_buckets:
return True
all_buckets[bucket_num] = nums[i]
if (bucket_num - 1) in all_buckets and abs(all_buckets[bucket_num - 1] - nums[i]) <= t:
return True
if (bucket_num + 1) in all_buckets and abs(all_buckets[bucket_num + 1] - nums[i]) <= t:
return True
if i >= k and i-k >= 0:
all_buckets.pop(nums[i-k]//bucket_size)
return False
反思: 当看到这道题时,说实话的,有点懵,看不懂题目究竟要干什么。思考了好一会后,决定去寻找题解的帮忙。这个方法使用使用桶排序的思想来处理这个问题,将元素根据其值的范围分配到不同的桶中。每个桶的大小为t+1,这样可以确保桶内的元素之间的差的绝对值不会超过t。然后,你检查当前元素的前一个和后一个桶,看是否存在元素的差的绝对值不超过t,然后就能解决问题。通过这个方法,我对桶排序有了更深的认识,收获很多。
3.0164.最大间距
描述:给定一个无序数组 nums。
要求:找出数组在排序之后,相邻元素之间最大的差值。如果数组元素个数小于 2,则返回 0。
class Solution:
def maximumGap(self, nums: List[int]) -> int:
n = len(nums)
if n < 2: return 0
res = 0
nums.sort()
for i in range(1, n):
res = max(res, nums[i] - nums[i - 1])
return res
反思:在一开始写这道题时,我曾想的是使用暴力解法,即用一个数组记录下每一个差值,最后在进行比较,但是这样花费的时间太多。于是我就上题解去浏览了一番,看到这个解法就惊叹了一声,看来还得再多多的学习。
Task03反思:整个Task03学习了很多排序的方法,让我对如何排序有了一种更清晰,更熟悉的感觉。这几天,感觉完成任务的时间很紧,除了在线上自主学习算法外,线下的课程与生活的杂事也有些多,导致不能很好的分配时间。因为有些排序的方法和题目,我会思考很久,努力地去理解其中地思路与思维。每天的任务虽然有点赶但都能完成,感觉coding已经占据了很大部分时间了。毕竟基础薄弱,但是我会努力的!