Task03-数组排序

第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已经占据了很大部分时间了。毕竟基础薄弱,但是我会努力的!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值