leetcode数组中的问题(一)

 

目录

283. 移动零

27. 移除元素

26. 删除排序数组中的重复项

80. 删除排序数组中的重复项 II

75. 颜色分类

88. 合并两个有序数组

215. 数组中的第K个最大元素

414. 第三大的数

167. 两数之和 II - 输入有序数组 

1. 两数之和


283. 移动零

https://leetcode-cn.com/problems/move-zeroes/submissions/

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:   输入: [0,1,0,3,12]   输出: [1,3,12,0,0]

思路

一:开辟一个新的数组用来存储非零元素,最终将该数组的值赋回原数组,剩下的元素填0

二:[0,none_zero]中是依据相对顺序存放的非零元素,若一个元素非零,则将其挪到none_zero+1的位置,并且none_zero加1,则此时[0,none_zero]中是依旧是依据相对顺序存放的非零元素;若是零元素,则不做任何处理

class Solution(object):
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        if not nums:
            return nums
        
        none_zero = -1
        for i in range(len(nums)):
            if nums[i] != 0:
                nums[i], nums[none_zero + 1] = nums[none_zero + 1], nums[i]
                none_zero += 1
        return nums

三:将非零数组往前移,并记录非零元素的下标([0,none_zero)中的元素都是非零元素),剩下的元素填0。

class Solution(object):
    def moveZeroes(self, nums):
        if not nums:
            return nums
        
        none_zero= 0

        for i in range(len(nums)):
            if nums[i]:
                nums[none_zero] = nums[i]
                none_zero += 1
        while none_zero < len(nums):
            nums[none_zero] = 0
            none_zero += 1
        
        return nums

27. 移除元素

https://leetcode-cn.com/problems/remove-element/

给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:给定 nums = [3,2,2,3], val = 3,函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。

示例 2:给定 nums = [0,1,2,2,3,0,4,2], val = 2,函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。

思路

一:对撞指针,i, j =0, n,其中n=len(nums)。[0,i)中的元素是被保留的元素(即值不为val),[j,n-1]中的元素是被移除的元素,初始状态符合条件以及被移除的均为空,i是正在遍历的元素,若该元素值不为val,归入到前面,只要i加1即可保证[0,i)中依旧是被保留元素,否则归入到后面,即nums[i] = nums[j - 1],且j减1。返回的时候,因为j是第一个未被保留的下标,即[0,j-1]是被保留的,则长度应为j。注:此法被移除的元素区域未必就是被移除元素的值,即不管被移除区域的值。

class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        if not nums:
            return 0
        
        i, j =0, len(nums)

        while i < j:
            if nums[i] == val:
                nums[i] = nums[j - 1]
                j -= 1
            else:
                i += 1
        return j  

26. 删除排序数组中的重复项

https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:给定数组 nums = [1,1,2], 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 你不需要考虑数组中超出新长度后面的元素。
示例 2:给定 nums = [0,0,1,1,1,2,2,3,3,4],函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。你不需要考虑数组中超出新长度后面的元素。

思路

一:[0,i]是被保留的元素(i初始值为0,因为第一个元素一定会被保留),j是正在遍历的元素。

在遍历j之前,[0,i]是被保留的元素;

在遍历j的时候,若j满足被保留的情况(原数组有序,若下标j的元素与i的元素不等则被保留,此时很明显可以满足每个元素只出现一次),则nums[i+1]=nums[j],且i+1,则[0,i]依旧是被保留的元素;若j应该被删除,则j直接加1,i不变,[0,i]依旧是被保留的元素。

class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) <= 1:
            return len(nums)
        i = 0

        for j in range(1, len(nums)):
            if nums[i] != nums[j]:
                nums[i + 1] = nums[j]
                i += 1
        return i + 1

80. 删除排序数组中的重复项 II

https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/submissions/

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:给定 nums = [1,1,1,2,2,3],函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。你不需要考虑数组中超出新长度后面的元素。
示例 2:给定 nums = [0,0,1,1,1,1,2,3,3],函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。你不需要考虑数组中超出新长度后面的元素。

思路

一:nums[0,reserve_id]存放的是被保留的元素。

class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) <= 2:
            return len(nums)
        reserve_id, now, count = -1, nums[0], 0

        for i in range(len(nums)):
            if nums[i] == now:
                if count >= 2:
                    continue
                nums[reserve_id + 1] = nums[i]
                reserve_id += 1
                count += 1
            else:
                now = nums[i]
                count = 1
                nums[reserve_id + 1] = nums[i]
                reserve_id += 1
        return reserve_id + 1

75. 颜色分类

https://leetcode-cn.com/problems/sort-colors/submissions/

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。注意:不能使用代码库中的排序函数来解决这道题。

示例:输入: [2,0,2,1,1,0],输出: [0,0,1,1,2,2]

思路

一:一个直观的解决方案是使用计数排序的两趟扫描算法。首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。

二;借用三路快排的思想,只扫描一遍,主要是明确每个变量的含义,或者区间的定义。

class Solution(object):
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        if len(nums) <= 1:
            return
        
        #[0,zero]- 0, [two, len(nums)-1] - 2, (zero, cur) - 1
        zero, two, cur = -1, len(nums), 0
        while cur < two:
            if nums[cur] == 0:
                nums[zero + 1], nums[cur] = nums[cur], nums[zero + 1]
                zero += 1
                cur += 1
            elif nums[cur] == 2:
                nums[two - 1], nums[cur] = nums[cur], nums[two - 1]
                two -= 1
            else:
                cur += 1
        return

88. 合并两个有序数组

https://leetcode-cn.com/problems/merge-sorted-array/submissions/

给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。说明:初始化 nums1 和 nums2 的元素数量分别为 m 和 n。你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:输入:nums1 = [1,2,3,0,0,0], m = 3,nums2 = [2,5,6],n = 3,输出: [1,2,2,3,5,6]

思路

一:从最大开始往最小排,避免要挪动nums1中的元素。

class Solution(object):
    def merge(self, nums1, m, nums2, n):
        """
        :type nums1: List[int]
        :type m: int
        :type nums2: List[int]
        :type n: int
        :rtype: None Do not return anything, modify nums1 in-place instead.
        """
        if not nums2:
            return 
        
        i_1, i_2, cur = m - 1, n - 1, m + n -1
        while i_1 >=0 or i_2 >= 0:
            if i_2 < 0:
                return 
            if i_1 < 0:
                nums1[cur] = nums2[i_2]
                i_2 -= 1
            elif nums1[i_1] >= nums2[i_2]:
                nums1[cur] = nums1[i_1]
                i_1 -= 1
            else:
                nums1[cur] = nums2[i_2]
                i_2 -= 1
            cur -= 1

        return

215. 数组中的第K个最大元素

https://leetcode-cn.com/problems/kth-largest-element-in-an-array/submissions/

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:输入: [3,2,1,5,6,4] 和 k = 2.  输出: 5.  

示例 2:输入: [3,2,3,1,2,4,5,5,6] 和 k = 4. 输出: 4

思路

一:借用快排思想,[l+1, j] >= val, (j,i) < val,如果是快速排序算法,会在这里递归地对两部分进行快速排序,时间复杂度为 O(NlogN)。而在这里,由于知道要找的第k大的元素在哪部分中,我们不需要对两部分都做处理,这样就将平均时间复杂度下降到 O(N)。

from random import randint
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        self._partition(nums, 0, len(nums) - 1, k - 1)
        # print(nums)
        return nums[k - 1]

    def _partition(self, nums, l, r, target):
        if l >= r:
            return 
        p = self._helper(nums, l, r)
        if p >= target:
            self._partition(nums, l, p - 1, target)
        else:
            self._partition(nums, p + 1, r, target)
    
    def _helper(self, nums, l, r):
        idx = randint(l, r)
        nums[l], nums[idx] = nums[idx], nums[l]
        val = nums[l]
        # [l+1, j] >= val, (j,i) < val
        j = l
        for i in range(l + 1, r + 1):
            if nums[i] >= val:
                nums[j + 1], nums[i] = nums[i], nums[j + 1]
                j += 1
        nums[j], nums[l] = nums[l], nums[j]
        return j

二:三路快排,[l+1, gt] > val, [lt, r] < val,(gt, i) = v。

from random import randint
class Solution(object):
    def findKthLargest(self, nums, k):
        self._partition(nums, 0, len(nums) - 1, k - 1)
        # print(nums)
        return nums[k - 1]

    def _partition(self, nums, l, r, target):
        if l >= r:
            return 
        gt, lt = self._helper(nums, l, r)
        if gt >= target:
            self._partition(nums, l, gt, target)
        elif lt <= target:
            self._partition(nums, lt, r, target)
    
    def _helper(self, nums, l, r):
        idx = randint(l, r)
        nums[l], nums[idx] = nums[idx], nums[l]
        val = nums[l]
        # [l+1, gt] > val, [lt, r] < val,(gt, i) = v
        gt, lt, i = l, r + 1, l + 1
        while i < lt:
            if nums[i] > val:
                nums[gt + 1], nums[i] = nums[i], nums[gt + 1]
                gt += 1
                i += 1
            elif nums[i] < val:
                nums[lt - 1], nums[i] = nums[i], nums[lt - 1]
                lt -= 1
            else:
                i += 1
        nums[l], nums[gt] = nums[gt], nums[l]
        return gt - 1, lt  

414. 第三大的数

https://leetcode-cn.com/problems/third-maximum-number/

给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。

示例 1:输入: [3, 2, 1],输出: 1,解释: 第三大的数是 1.
示例 2:输入: [1, 2],输出: 2,解释: 第三大的数不存在, 所以返回最大的数 2 .
示例 3:输入: [2, 2, 3, 1],输出: 1,解释: 注意,要求返回第三大的数,是指第三大且唯一出现的数。存在两个值为2的数,它们都排第二。

思路

一:先去重,再维护一个至遍历到的所有元素的最大三个值的数组。

class Solution(object):
    def thirdMax(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        new_nums = list(set(nums))
        n = len(new_nums)
        if n < 3:
            return max(new_nums)
        sort_3 = sorted(new_nums[0: 3], reverse=True)

        for i in range(3, len(new_nums)):
            # 维护[0,i]的最大的三个元素
            self._if_in(sort_3, new_nums[i])
        return sort_3[-1]

    def _if_in(self, sort_3, num):
        if num < sort_3[2]:
            return
        if sort_3[2] < num < sort_3[1]:
            sort_3[2] = num
        elif sort_3[1] < num < sort_3[0]:
            sort_3[2], sort_3[1] = sort_3[1], num
        else:
            sort_3[2], sort_3[1], sort_3[0] = sort_3[1], sort_3[0], num

二:展示一下优先队列。

class Solution(object):
    def thirdMax(self, nums):、
        new_nums = list(set(nums))
        n = len(new_nums)
        if n < 3:
            return max(new_nums)
        return heapq.nlargest(3, new_nums)[2]

167. 两数之和 II - 输入有序数组 

https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/submissions/

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。说明:返回的下标值(index1 和 index2)不是从零开始的。你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:输入: numbers = [2, 7, 11, 15], target = 9,输出: [1,2],解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

思路

一:双层遍历,时间复杂度O(n^2)

二:利用有序性,对每一个下标i,二分查找遍历剩余的数组,看看是否有符合要求的target - nums[i],时间复杂度O(nlgn)

三:对撞指针,从两头向中间遍历,时间复杂度O(n)

class Solution(object):
    def twoSum(self, numbers, target):
        """
        :type numbers: List[int]
        :type target: int
        :rtype: List[int]
        """
        i, j = 0, len(numbers) - 1
        while i < j:
            if numbers[i] + numbers[j] == target:
                return [i + 1, j + 1]
            if numbers[i] + numbers[j] > target:
                j -= 1
            else:
                i += 1

1. 两数之和

https://leetcode-cn.com/problems/two-sum/submissions/

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:给定 nums = [2, 7, 11, 15], target = 9,因为 nums[0] + nums[1] = 2 + 7 = 9,所以返回 [0, 1]

思路

一:借用哈希表,python中字典和集合的底层实现均是哈希表。

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        rec = {nums[0]: 0}
        for i in range(1, len(nums)):
            t = target - nums[i]
            if t in rec:
                return [rec[t], i]
            rec[nums[i]] = i
发布了46 篇原创文章 · 获赞 1 · 访问量 5045

猜你喜欢

转载自blog.csdn.net/qq_xuanshuang/article/details/104189858