leetcode数组中的问题(九)

目录

532. 数组中的K-diff数对

581. 最短无序连续子数组

914. 卡牌分组


849. 到最近的人的最大距离

https://leetcode-cn.com/problems/maximize-distance-to-closest-person/

在一排座位( seats)中,1 代表有人坐在座位上,0 代表座位上是空的。至少有一个空座位,且至少有一人坐在座位上。亚历克斯希望坐在一个能够使他与离他最近的人之间的距离达到最大化的座位上。返回他到离他最近的人的最大距离。

示例 1:输入:[1,0,0,0,1,0,1],输出:2
解释:如果亚历克斯坐在第二个空位(seats[2])上,他到离他最近的人的距离为 2 。如果亚历克斯坐在其它任何一个空位上,他到离他最近的人的距离为 1 。因此,他到离他最近的人的最大距离是 2 。 
示例 2:输入:[1,0,0,0],输出:3
解释: 如果亚历克斯坐在最后一个座位上,他离最近的人有 3 个座位远。这是可能的最大距离,所以答案是 3 。
提示:1 <= seats.length <= 20000,seats 中只含有 0 和 1,至少有一个 0,且至少有一个 1。

思路

一:双指针法,[l,r]中只有l和r上有人,则这段空位到最近的人的距离为(r - l) / 2,最左端和最右端有点特殊,需要单独处理。

class Solution(object):
    def maxDistToClosest(self, seats):
        """
        :type seats: List[int]
        :rtype: int
        """
        res, l, r = 0, 0, 0
        # 处理最左端是空位的情况
        while l < len(seats):
            if seats[l] == 1:
                break
            l += 1
        res = l - 0
        r = l + 1
        # [l,r]
        while r < len(seats):
            if seats[r] == 1:
                res = max(res, (r - l) // 2)
                l = r
            r += 1
        # 处理最右端是空位的情况
        if seats[-1] == 0:
            res = max(res, len(seats) - 1 - l)
        return res

532. 数组中的K-diff数对

https://leetcode-cn.com/problems/k-diff-pairs-in-an-array/

给定一个整数数组和一个整数 k, 你需要在数组里找到不同的 k-diff 数对。这里将 k-diff 数对定义为一个整数对 (i, j), 其中 i 和 j 都是数组中的数字,且两数之差的绝对值是 k.

示例 1:输入: [3, 1, 4, 1, 5], k = 2,输出: 2
解释: 数组中有两个 2-diff 数对, (1, 3) 和 (3, 5)。尽管数组中有两个1,但我们只应返回不同的数对的数量。
示例 2:输入:[1, 2, 3, 4, 5], k = 1,输出: 4
解释: 数组中有四个 1-diff 数对, (1, 2), (2, 3), (3, 4) 和 (4, 5)。
示例 3:输入: [1, 3, 1, 5, 4], k = 0,输出: 1
解释: 数组中只有一个 0-diff 数对,(1, 1)。
注意:数对 (i, j) 和数对 (j, i) 被算作同一数对。数组的长度不超过10,000。所有输入的整数的范围在 [-1e7, 1e7]。

思路

一:先排序加双指针,将k=0的情况单拎出来,若存在两个以上相同的数算一个解;若k!=0跳过重复的元素寻找。若不单独处理k=0的情况,例[1,1,3,4 ,5] ,k=0,l和r可能相等,(0, 1) (2, 2) (3, 3) (4, 4)。

class Solution(object):
    def findPairs(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        # 特判,看的评论,绝对值不可能为负,直接返回0
        if k < 0 or len(nums) < 2:
            return 0
        nums = sorted(nums)
        # k = 0特判
        if k == 0:
            v, count, cnt = nums[0], 0, 1
            for i in range(1, len(nums)):
                if nums[i] == v:
                    cnt += 1
                else:
                    if cnt >= 2:
                        count += 1
                    v = nums[i]
                    cnt = 1
            if nums[-1] == nums[-2]:
                count += 1
            return count

        l, r = 0, 1
        count = 0

        while r < len(nums):
            if nums[r] - nums[l] < k:
                r += 1
            elif nums[r] - nums[l] == k:
                count += 1
                r += 1
                l += 1
                # 跳过重复值,避免相同解,若k=0通过这种方法,会导致l有可能等于r,会多出解
                while r < len(nums) and nums[r] == nums[r - 1]:
                    r += 1
                # 跳过重复值,避免相同解
                while l < len(nums) and nums[l] == nums[l - 1]:
                    l += 1
            else:
                l += 1
        return count
                

二:排序后遍历数组,定义快慢指针,r为快指针,l为慢指针,同时定义prev变量来记录前一个符合要求的字符,避免重复字符的影响。此处可以保证l>r。

class Solution(object):
    def findPairs(self, nums, k):
        # 特判,看的评论,绝对值不可能为负,直接返回0
        if k < 0 or len(nums) < 2:
            return 0
        nums = sorted(nums)

        l, prev = 0, nums[0] - 1
        count = 0

        for r in range(1, len(nums)):
            while (nums[r] - nums[l] > k or nums[l] == prev) and (r != l + 1):
                l += 1
            if nums[r] - nums[l] == k and nums[l] != prev:
                count += 1
                prev = nums[l]
                l += 1
        
        return count

三:借助哈希表,saw存放的是以访问的数据,diff中存放的是K-diff数对其中的一个数,且集合不含重复元素,可利用该特性去重。

class Solution(object):
    def findPairs(self, nums, k):
        if k < 0:
            return 0
        saw, diff = set(), set()
        for num in nums:
            if num - k in saw:
                diff.add(num-k)
            if num + k in saw:
                diff.add(num)
            saw.add(num)
        return len(diff)

581. 最短无序连续子数组

https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/

给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。你找到的子数组应是最短的,请输出它的长度。

示例 1:输入: [2, 6, 4, 8, 10, 9, 15],输出: 5
解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。
说明 :输入的数组长度范围在 [1, 10,000]。输入的数组可能包含重复元素 ,所以升序的意思是<=。

思路

一:先排序,从两边找出不对的位置,即可。

class Solution(object):
    def findUnsortedSubarray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        helper = sorted(nums)

        l, r = 0, len(nums) - 1

        while l < len(nums):
            if helper[l] != nums[l]:
                break
            l += 1
        
        while r >= 0:
            if helper[r] != nums[r]:
                break
            r -= 1
        if r > l:
            return r - l + 1
        return 0

二:转自https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/solution/java-ji-bai-100-shi-jian-fu-za-du-on-kong-jian-fu-/大神的题解,

一个例子明白下面的算法
输入[2, 3, 11, 8, 10, 9, 15, 22]
算法流程:
从左往右遍历数组, 发现{15, 22}是递增的, 同时15比前面所有的元素都大, 说明{15, 22}的位置已经固定了
从右往左遍历数组, 发现{2, 3}是递增的, 同时3比右边所有的元素都小, 所以{2,3}的位置也已经固定了

经过两遍遍历之后发现{2,3}和{15,22}不用排序了,只需要将{11, 8, 10, 9}这4个元素排序即可, 所以最终输出4
遍历的过程就是在找哪些元素位置已经固定, 不需要排序了

首先明确两个变量的含义,r表示[r n-1]范围上的元素不用排序,l表示[0, l-1]范围上的元素不用排序,所以最终需要排序的连续子数组范围是[l r], 一共有r-l+1个元素

接下来是遍历过程
从左往右遍历数组, 记录nums[i]左侧的最大值, 如果nums[i]>=cur_max, 就更新cur_max, 如果nums[i]<max, 则使用变量r记录索引i; 遍历结束后,r右侧的部分不需要排序. (r左侧的部分可能需要全部排序或者部分排序,需要根据从右往左遍历的结果决定)

从右往左遍历数组, 记录arr[i]右侧的最小值, 如果nums[i]<=cur_min, 就更新cur_min, 如果nums[i]>cur_min, 则使用变量l记录索引i; 遍历结束后, l左侧的部分不需要排序

这两遍遍历做的事情: 找到递增的部分

class Solution(object):
    def findUnsortedSubarray(self, nums):
        n = len(nums)
        l, r = -1, -1
        cur_max, cur_min = nums[0], nums[n - 1]

        for i in range(n):
            if cur_max <= nums[i]:
                cur_max = nums[i]
            else:
                r = i
        for i in range(n - 1, -1, -1):
            if cur_min >= nums[i]:
                cur_min = nums[i]
            else:
                l = i
        if r > l:
            return r - l + 1
        return 0

914. 卡牌分组

https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/

给定一副牌,每张牌上都写着一个整数。此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组:每组都有 X 张牌。组内所有的牌上都写着相同的整数。仅当你可选的 X >= 2 时返回 true。

示例 1:输入:[1,2,3,4,4,3,2,1],输出:true
解释:可行的分组是 [1,1],[2,2],[3,3],[4,4]
示例 2:输入:[1,1,1,2,2,2,3,3],输出:false
解释:没有满足要求的分组。
示例 3:输入:[1],输出:false
解释:没有满足要求的分组。
示例 4:输入:[1,1],输出:true
解释:可行的分组是 [1,1]
示例 5:输入:[1,1,2,2,2,2],输出:true
解释:可行的分组是 [1,1],[2,2],[2,2]

提示:1 <= deck.length <= 10000,0 <= deck[i] < 10000

思路

一:copy官方题解,https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/solution/qia-pai-fen-zu-by-leetcode/,同理假设 rec[num] 是数字 num的卡片个数,同样对于所有的num 满足rec[num] % X == 0,其中每堆有 X 张卡片。因此,X 一定可以整除rec[num] 的最大公约数。如果最大公约数 g 超过 1,那么就有 X = g 满足条件,否则不满足条件。

from collections import defaultdict
class Solution(object):
    def hasGroupsSizeX(self, deck):
        """
        :type deck: List[int]
        :rtype: bool
        """
        n = len(deck)
        if n <= 1:
            return False
 
        rec = defaultdict(int)
        for num in deck:
            rec[num] += 1

        g = self._gcd(rec[deck[0]], rec[deck[0]])
        for k, v in rec.items():
            g = self._gcd(g, v)
        if g != 1:
            return True
        return False

    # 求最大公约数
    def _gcd(self,a,b):
        if a % b == 0:
            return b
        return self._gcd(b, a % b)

 

发布了46 篇原创文章 · 获赞 1 · 访问量 5047

猜你喜欢

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