leetcode数组中的问题(十)

目录

4. 寻找两个正序数组的中位数

1470. 重新排列数组

1486. 数组异或操作

1295. 统计位数为偶数的数字

1534. 统计好三元组

1460. 通过翻转子数组使两个数组相等

1550. 存在连续三个奇数的数组

1122. 数组的相对排序

1337. 方阵中战斗力最弱的 K 行

268. 缺失数字


4. 寻找两个正序数组的中位数

https://leetcode-cn.com/problems/median-of-two-sorted-arrays/

给定两个大小为 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

题解

一:转自官方题解:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xun-zhao-liang-ge-you-xu-shu-zu-de-zhong-wei-s-114/

给定两个有序数组,要求找到两个有序数组的中位数,最直观的思路有以下两种:

  • 使用归并的方式,合并两个有序数组,得到一个大的有序数组。大的有序数组的中间位置的元素,即为中位数。
  • 不需要合并两个有序数组,只要找到中位数的位置即可。由于两个数组的长度已知,因此中位数对应的两个数组的下标之和也是已知的。维护两个指针,初始时分别指向两个数组的下标 0 的位置,每次将指向较小值的指针后移一位(如果一个指针已经到达数组末尾,则只需要移动另一个数组的指针),直到到达中位数的位置。

假设两个有序数组的长度分别为 m 和 n,上述两种思路的复杂度如何?第一种思路的时间复杂度是 O(m+n),空间复杂度是 O(m+n)。第二种思路虽然可以将空间复杂度降到O(1),但是时间复杂度仍是 O(m+n)。题目要求时间复杂度是O(log(m+n)),因此上述两种思路都不满足题目要求的时间复杂度。

如何把时间复杂度降低到 O(log(m+n)) 呢?如果对时间复杂度的要求有 log,通常都需要用到二分查找,这道题也可以通过二分查找实现。根据中位数的定义,当 m+n 是奇数时,中位数是两个有序数组中的第 (m+n)/2 个元素,当 m+n 是偶数时,中位数是两个有序数组中的第 (m+n)/2 个元素和第 (m+n)/2+1 个元素的平均值。因此,这道题可以转化成寻找两个有序数组中的第 k小的数,其中 k 为 (m+n)/2 或 (m+n)/2+1。

假设两个有序数组分别是 A 和 B。要找到第 k 个元素,我们可以比较 A[k/2−1] 和 B[k/2−1],其中 / 表示整数除法。由于 A[k/2−1] 和 B[k/2−1] 的前面分别有 A[0..k/2−2] 和 B[0..k/2−2],即 k/2−1 个元素,对于 A[k/2−1] 和 B[k/2−1] 中的较小值,最多只会有 (k/2−1)+(k/2−1)≤k−2 个元素比它小,那么它就不能是第 k 小的数了。

因此我们可以归纳出三种情况:

  1. 如果 A[k/2−1]<B[k/2−1],则比 A[k/2−1] 小的数最多只有 A 的前 k/2−1 个数和 B 的前 k/2−1 个数,即比 A[k/2−1] 小的数最多只有 k−2 个,因此 A[k/2−1] 不可能是第 k 个数,A[0] 到 A[k/2−1] 也都不可能是第 k 个数,可以全部排除。
  2. 如果 A[k/2−1]>B[k/2−1],则可以排除 B[0] 到 B[k/2−1]。
  3. 如果 A[k/2−1]=B[k/2−1],则可以归入第一种情况处理。

fig1

可以看到,比较 A[k/2−1] 和 B[k/2−1] 之后,可以排除 k/2 个不可能是第 k 小的数,查找范围缩小了一半。同时,我们将在排除后的新数组上继续进行二分查找,并且根据我们排除数的个数,减少 k 的值,这是因为我们排除的数都不大于第 
k 小的数。

有以下三种情况需要特殊处理:

  1. 如果 A[k/2−1] 或者 B[k/2−1] 越界,那么我们可以选取对应数组中的最后一个元素。在这种情况下,我们必须根据排除数的个数减少 k 的值,而不能直接将 k减去 k/2。
  2. 如果一个数组为空,说明该数组中的所有元素都被排除,我们可以直接返回另一个数组中第 k 小的元素。
  3. 如果 k=1,我们只要返回两个数组首元素的最小值即可。

用一个例子说明上述算法。假设两个有序数组如下:

A: 1 3 4 9
B: 1 2 3 4 5 6 7 8 9
两个有序数组的长度分别是 4 和 9,长度之和是 13,中位数是两个有序数组中的第 7 个元素,因此需要找到第 k=7 个元素。

class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        def getKthElement(nums1, nums2, k):
            n1, n2 = len(nums1), len(nums2)
            index1, index2 = 0, 0
            while True:
                if index1 == n1:
                    return nums2[index2 + k - 1]
                if index2 == n2:
                    return nums1[index1 + k - 1]
                if k == 1:
                    return min(nums1[index1], nums2[index2])

                half = k // 2 
                newIndex1 = min(index1 + half, n1) - 1
                newIndex2 = min(index2 + half, n2) - 1

                if nums1[newIndex1] <= nums2[newIndex2]:
                    k -= (newIndex1 - index1 + 1)
                    index1 = newIndex1 + 1
                else:
                    k -= (newIndex2 - index2 + 1)
                    index2 = newIndex2 + 1
        
        n1, n2 = len(nums1), len(nums2)
        totalLen = n1 + n2 
        res = 0
        if totalLen % 2 == 0:
            res += getKthElement(nums1, nums2, totalLen // 2)
            res += getKthElement(nums1, nums2, totalLen // 2 + 1)
            return res * 1.0 / 2
        else:
            return getKthElement(nums1, nums2, totalLen // 2 + 1) * 1.0

1470. 重新排列数组

https://leetcode-cn.com/problems/shuffle-the-array/

给你一个数组 nums ,数组中有 2n 个元素,按 [x1,x2,...,xn,y1,y2,...,yn] 的格式排列。请你将数组按 [x1,y1,x2,y2,...,xn,yn] 格式重新排列,返回重排后的数组。

示例 1:输入:nums = [2,5,1,3,4,7], n = 3,输出:[2,3,5,4,1,7] 
解释:由于 x1=2, x2=5, x3=1, y1=3, y2=4, y3=7 ,所以答案为 [2,3,5,4,1,7]
示例 2:输入:nums = [1,2,3,4,4,3,2,1], n = 4,输出:[1,4,2,3,3,2,4,1]
示例 3:输入:nums = [1,1,2,2], n = 2,输出:[1,2,1,2]
提示:1 <= n <= 500,nums.length == 2n,1 <= nums[i] <= 10^3

题解

一:非原址排序,O(n)的空间复杂度,O(n)的时间复杂度。

res[2 * i], res[2 * i + 1] = nums[i], nums[n + i]

二:转自https://leetcode-cn.com/problems/shuffle-the-array/solution/kong-jian-fu-za-du-wei-o1-de-liang-chong-jie-fa-by/,因为题目限制了每一个元素 nums[i] 最大只有可能是 1000,这就意味着每一个元素只占据了 10 个 bit。(2^10 - 1 = 1023 > 1000)。而一个 int 有 32 个 bit,所以我们还可以使用剩下的 22 个 bit 做存储。实际上,每个 int,我们再借 10 个 bit 用就好了。因此,在下面的代码中,每一个 nums[i] 的最低的十个 bit(0-9 位),我们用来存储原来 nums[i] 的数字;再往前的十个 bit(10-19 位),我们用来存储重新排列后正确的数字是什么。在循环中,我们每次首先计算 nums[i] 对应的重新排列后的索引 j,之后,取 nums[i] 的低 10 位(nums[i] & 1023),这边注意nums[i] & 1023很重要,表示只取低10位,即只取原先的i下标的数字,由于nums[i]的高位有可能已经存放了正确排列后的数字,所以要和1023做&,即 nums[i] 的原始信息,把他放到 nums[j] 的高十位上。最后,每个元素都取高 10 位的信息(e >> 10),即是答案。

class Solution(object):
    def shuffle(self, nums, n):

        for i in range(2 * n):
            j = 2 * i if i < n else (i - n) * 2 + 1 
            nums[j] |= ((nums[i] & 1023) << 10)

        for i in range(2 * n):
            nums[i] >>= 10
        return nums

三:转自https://leetcode-cn.com/problems/shuffle-the-array/solution/kong-jian-fu-za-du-wei-o1-de-liang-chong-jie-fa-by/利用题目中限制每一个元素 nums[i] 都大于 0。我们可以使用负数做标记标记什么?标记当前 nums[i] 存储的数字,是不是重新排列后的正确数字。如果是,存负数;如果不是,存正数(即原本的数字,还需处理)

我们每次处理一个 nums[i],计算这个 nums[i] 应该放置的正确位置 j。但是,nums[j] 还没有排列好,所以我们暂时把 nums[j] 放到 nums[i] 的位置上来,并且记录上,此时 nums[i] 的元素本来的索引是 j。现在,我们就可以安心地把 nums[i] 放到 j 的位置了。同时,因为这已经是 nums[i] 正确的位置,取负数,即标记这个位置已经存放了正确的元素。只要有原始下标我们每次都能确定当前数值应该存放的下标,挪过去,但是会导致覆盖一个位置,这时我们可以将这个值挪到下标i,即交换两个下标的值,且其原始下标我们也知道,即是j。

之后,我们继续处理当前的 nums[i],注意,此时这个新的 nums[i],本来的索引是 j。所以我们根据 j 算出它应该存放的位置,然后把这个位置的元素放到 nums[i] 中,取负做标记。

这个过程以此类推。这就是代码中 while 循环做的事情。

直到 nums[i] 的值也是负数,说明 i 的位置也已经是重新排列后的正确元素了,我们就可以看下一个位置了。

在 for 循环中,如果某一个元素已经是小于零了,说明这个位置已经是正确元素了,可以忽略。

这个算法虽然有两重循环,但是时间复杂度是 O(n) 的,因为每个元素最多会被重新排列一次,然后会被最外面的 for 循环访问一次。一旦重新排列过,for 的访问只是一次 if 判断而已。

当然,最后,数组中的所有元素还需要从负数转换回正数。

class Solution(object):
    def shuffle(self, nums, n):

        for i in range(2 * n):
            j = i 
            while nums[i] > 0:
                j = 2 * j if j < n else (j - n) * 2 + 1
                nums[i], nums[j] = nums[j], nums[i]
                nums[j] *= -1
        
        return [-1 * num for num in nums]

1486. 数组异或操作

https://leetcode-cn.com/problems/xor-operation-in-an-array/

给你两个整数,n 和 start 。数组 nums 定义为:nums[i] = start + 2*i(下标从 0 开始)且 n == nums.length 。请返回 nums 中所有元素按位异或(XOR)后得到的结果。

示例 1:输入:n = 5, start = 0,输出:8

解释:数组 nums 为 [0, 2, 4, 6, 8],其中 (0 ^ 2 ^ 4 ^ 6 ^ 8) = 8 。"^" 为按位异或 XOR 运算符。
示例 2:输入:n = 4, start = 3,输出:8
解释:数组 nums 为 [3, 5, 7, 9],其中 (3 ^ 5 ^ 7 ^ 9) = 8.
示例 3:输入:n = 1, start = 7,输出:7
示例 4:输入:n = 10, start = 5,输出:2
提示:1 <= n <= 1000,0 <= start <= 1000,n == nums.length

题解

一:暴力解法,一重for 循环遍历所有值做异或,时间复杂度O(n)。

二:利用异或的性质,转自https://leetcode-cn.com/problems/xor-operation-in-an-array/solution/o1-wei-yun-suan-by-bruceyuj/,XOR 有很多有用的特性:

我们来看看题目的要求:

你会发现题目的要求和上面我们列举的特性 3 很像,只是异或元素每次都是递增 2。因此,我们可以对题目进行一次处理,也就是对所有异或元素右移一位,得到 

相当于我们将最终结果向右移动了一位,那么最后一位是什么呢?
我们会发现最后一位是由 start 和 数组长度 n 决定的。这是由于 2,4,... 这些转换成二进制后最后一位都是 0。

  • 因此如果 start 是偶数,那么最后一位肯定是 0.
  • 如果 start 是奇数,但是 n 是偶数,这里我们使用特性 1,得到最后一位也是 0.
  • 其他情况下,最后一位是 1.

class Solution(object):
    def xorOperation(self, n, start):
        """
        :type n: int
        :type start: int
        :rtype: int
        """
        def xor(n, start):
            if start & 1: # 奇数
                return (start - 1) ^ helper(n + 1, start - 1)
            else:
                return helper(n, start)
        
        # start 必是偶数
        def helper(n, start):
            if n & 1: # n是奇数, (n - 1)//2 个1异或,(n - 1)//2偶数0,奇数1, 还有最后一个数异或上
                return ((n // 2) & 1) ^ (start + n - 1)
            else: # n是偶数, n//2 个1异或,n//2偶数0,奇数1
                return (n // 2) & 1

        # 相当于我们将最终结果向右移动了一位,那么最后一位是什么呢?
        ans = 2 * xor(n, start // 2)
        # 我们会发现最后一位是由 start 和 数组长度 n 决定的。
        # 这是由于 2,4,... 这些转换成二进制后最后一位都是 0。
        if start & n & 1:
            ans += 1 
        return ans

1295. 统计位数为偶数的数字

https://leetcode-cn.com/problems/find-numbers-with-even-number-of-digits/

给你一个整数数组 nums,请你返回其中位数为 偶数 的数字的个数。

示例 1:输入:nums = [12,345,2,6,7896],输出:2
解释:12 是 2 位数字(位数为偶数),345 是 3 位数字(位数为奇数),  
2 是 1 位数字(位数为奇数),6 是 1 位数字 位数为奇数) ,
7896 是 4 位数字(位数为偶数) ,因此只有 12 和 7896 是位数为偶数的数字
示例 2:输入:nums = [555,901,482,1771],输出:1 
解释: 只有 1771 是位数为偶数的数字。
提示:1 <= nums.length <= 500,1 <= nums[i] <= 10^5

题解:

一:借助字符串,位数即字符串长度

class Solution(object):
    def findNumbers(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        return len(list(filter(lambda item: len(str(item)) % 2 == 0, 
                               nums)))
class Solution(object):
    def findNumbers(self, nums):
        return sum(1 for num in nums if len(str(num)) % 2 == 0)

二:log函数

class Solution(object):
    def findNumbers(self, nums):
        return sum(1 for num in nums 
                    if (int(math.log10(num)) + 1) % 2 == 0)

1534. 统计好三元组

https://leetcode-cn.com/problems/count-good-triplets/

给你一个整数数组 arr ,以及 a、b 、c 三个整数。请你统计其中好三元组的数量。如果三元组 (arr[i], arr[j], arr[k]) 满足下列全部条件,则认为它是一个 好三元组 。

0 <= i < j < k < arr.length
|arr[i] - arr[j]| <= a
|arr[j] - arr[k]| <= b
|arr[i] - arr[k]| <= c
其中 |x| 表示 x 的绝对值。返回 好三元组的数量 。

示例 1:输入:arr = [3,0,1,1,9,7], a = 7, b = 2, c = 3,输出:4
解释:一共有 4 个好三元组:[(3,0,1), (3,0,1), (3,1,1), (0,1,1)] 。
示例 2:输入:arr = [1,1,2,2,3], a = 0, b = 0, c = 1,输出:0
解释:不存在满足所有条件的三元组。
提示:3 <= arr.length <= 100,0 <= arr[i] <= 1000,0 <= a, b, c <= 1000

题解

一:暴力枚举三重循环

二:借用字典,类似于求三数和以及四数和的。时间复杂度 O(n^2+nS),n 是 arr 的规模,S 是 arr 取值的规模。最终改善效果不明显。依据 jk 的值去界定 i 的范围。其中 rec 记录的是 arr[i]的值,因为 k 总是比 j 大,rec 又总是在 j 循环完美一个 k 的可能性后记录的,及下一次循环时,i 一定比 j 小,也可保证不是同一个下标。可以放心的使用。

class Solution(object):
    def countGoodTriplets(self, arr, a, b, c):
        """
        :type arr: List[int]
        :type a: int
        :type b: int
        :type c: int
        :rtype: int
        """
        rec = defaultdict(int)
        n, ans = len(arr), 0
        for j in range(0, n):
            for k in range(j + 1, n):
                if abs(arr[j] - arr[k]) <= b:
                    jl, jr = arr[j] - a, arr[j] + a
                    kl, kr = arr[k] - c, arr[k] + c
                    l = max(max(jl, kl), 0)
                    r = min(min(jr, kr), 1000)
                    if l <= r:
                        r = min(r, 1000)
                        ans += rec[r] - rec[l - 1] if l >= 1 else rec[r]
            for i in range(arr[j], 1001):
                rec[i] += 1
        return ans

1460. 通过翻转子数组使两个数组相等

https://leetcode-cn.com/problems/make-two-arrays-equal-by-reversing-sub-arrays/

给你两个长度相同的整数数组 target 和 arr 。每一步中,你可以选择 arr 的任意 非空子数组 并将它翻转。你可以执行此过程任意次。如果你能让 arr 变得与 target 相同,返回 True;否则,返回 False 。

示例 1:输入:target = [1,2,3,4], arr = [2,4,1,3],输出:true
解释:你可以按照如下步骤使 arr 变成 target:
1- 翻转子数组 [2,4,1] ,arr 变成 [1,4,2,3]
2- 翻转子数组 [4,2] ,arr 变成 [1,2,4,3]
3- 翻转子数组 [4,3] ,arr 变成 [1,2,3,4]
上述方法并不是唯一的,还存在多种将 arr 变成 target 的方法。
示例 2:输入:target = [7], arr = [7],输出:true
解释:arr 不需要做任何翻转已经与 target 相等。
示例 3:输入:target = [1,12], arr = [12,1],输出:true
示例 4:输入:target = [3,7,9], arr = [3,7,11],输出:false
解释:arr 没有数字 9 ,所以无论如何也无法变成 target 。
示例 5:输入:target = [1,1,1,1,1], arr = [1,1,1,1,1],输出:true
提示:target.length == arr.length,1 <= target.length <= 1000,1 <= target[i] <= 1000,1 <= arr[i] <= 1000

思路:

不写题解了,乍一看这题不好下手但标签是 easy。从测试用例可以大致看到或许看看两个数组排序之后是否相等。事实证明还真是。贴一大佬的题解,https://leetcode-cn.com/problems/make-two-arrays-equal-by-reversing-sub-arrays/solution/kan-zhao-hen-xia-ren-shi-ji-bi-jiao-liang-ge-shu-z/看着很吓人,实际比较两个数组元素是否完全相同(简单证明),

要是没有样例的启发,这题肯定把我难住了,其实就是判断两个数组元素是否相同。
证明也很简单,需要知道冒泡排序的过程,如果不知道可以学习一下。
冒泡排序的所有操作都是不断交换相邻两个元素的过程,交换相邻两个元素的操作也是反转子数组的一种。
考虑数组target,它一定可以通过冒泡排序变成递增(递减)的数组。假设我们记录下每一次的交换,记为操作序列A。
考虑数组 arr,它也一定可以通过冒泡排序变成递增(递减)的数组。
如果target与arr元素相同,那么最终冒泡排序结果也相同。将数组arr进行冒泡排序,再进行操作序列A的逆过程,就一定可以得到target。
如果数组target的元素与数组arr的元素不同,显然无法通过arr得到target。

1550. 存在连续三个奇数的数组

https://leetcode-cn.com/problems/three-consecutive-odds/

给你一个整数数组 arr,请你判断数组中是否存在连续三个元素都是奇数的情况:如果存在,请返回 true ;否则,返回 false 。

示例 1:输入:arr = [2,6,4,1],输出:false,解释:不存在连续三个元素都是奇数的情况。
示例 2:输入:arr = [1,2,34,3,4,5,7,23,12],输出:true,解释:存在连续三个元素都是奇数的情况,即 [5,7,23] 。
提示:1 <= arr.length <= 1000,1 <= arr[i] <= 1000

思路

一:滑动指针,右指针每次均右移。左指针总是挪到最近的偶数位,所以当 r 在奇数位时,此时 r - l 就是目前最长连续奇数的数目。

class Solution(object):
    def threeConsecutiveOdds(self, arr):
        """
        :type arr: List[int]
        :rtype: bool
        """
        n = len(arr)
        if n <= 2:
            return False
        # l - 偶数所引, 离目前奇数最近的偶数索引
        l = -1
        for r in range(n):
            if arr[r] % 2:
                # r - 此时是奇数,r - l 就是目前最长的连续奇数位
                if r - l  >= 3:
                    return True 
            else:
                l = r 
        return False

二:看了看题解,用 num 来记录连续奇数的数目,遇到奇数+1,偶数清零。

class Solution(object):
    def threeConsecutiveOdds(self, arr):
        n = len(arr)
        if n <= 2:
            return False
        num = 0
        for i in range(n):
            if arr[i] % 2:
                num += 1
                if num >= 3:
                    return True 
            else:
                num = 0
        return False

1122. 数组的相对排序

https://leetcode-cn.com/problems/relative-sort-array/

给你两个数组,arr1 和 arr2,arr2 中的元素各不相同, arr2 中的每个元素都出现在 arr1 中, 对 arr1 中的元素进行排序,使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。

示例:输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6], 输出:[2,2,2,1,4,3,3,9,6,7,19]
提示:arr1.length, arr2.length <= 1000, 0 <= arr1[i], arr2[i] <= 1000, arr2 中的元素 arr2[i] 各不相同, arr2 中的每个元素 arr2[i] 都出现在 arr1 中

题解

一:字典+自定义比较函数, 将arr2中的值-索引映射成字典,再将arr1排序后其中不在arr2中的值按递增映射成字典.最后按字典的值排序.

class Solution(object):
    def relativeSortArray(self, arr1, arr2):
        """
        :type arr1: List[int]
        :type arr2: List[int]
        :rtype: List[int]
        """
        comp = {arr2[i]: i for i in range(len(arr2))}
        arr1 = sorted(arr1)

        id_inc = len(arr2)
        for num in arr1:
            if num not in comp:
                comp[num] = id_inc
                id_inc += 1
        
        return sorted(arr1, key=lambda a: comp[a])

二:借鉴大神的计数排序https://leetcode-cn.com/problems/relative-sort-array/solution/ming-que-bi-jiao-fang-shi-hou-xiang-zen-yao-pai-ji/, 这一题第一反应是自定义比较函数,然后再进行排序,但是做完之后参考发现,最简单的是用计数排序,充分利用了题目所给提示信息思路也很清晰,先将arr1中的数全都记录到数组count中,然后遍历arr2的同时,将arr2中的数置入arr1,注意由于arr2中的数在arr1中也出现了,所以直接从count中取出即可处理好arr2之后,再处理剩下的数字,一格一格往里填就好了.

class Solution(object):
    def relativeSortArray(self, arr1, arr2):
        rec = [0] * 1001
        # 先将arr1中的数全都记录到数组rec中
        for a in arr1:
            rec[a] += 1

        ans, i = arr1[:], 0
        # 然后遍历arr2的同时,注意由于arr2中的数在arr1中也出现了,所以直接从count中取出即可处理好arr2之后
        for a2 in arr2:
            while rec[a2] > 0:
                ans[i] = a2
                i += 1
                rec[a2] -= 1
        # 再处理剩下的数字,一格一格往里填就好了
        for num in range(1001):
            while rec[num] > 0:
                ans[i] = num 
                i += 1
                rec[num] -= 1
        return ans

1337. 方阵中战斗力最弱的 K 行

https://leetcode-cn.com/problems/the-k-weakest-rows-in-a-matrix/

给你一个大小为 m * n 的方阵 mat,方阵由若干军人和平民组成,分别用 1 和 0 表示。请你返回方阵中战斗力最弱的 k 行的索引,按从最弱到最强排序。如果第 i 行的军人数量少于第 j 行,或者两行军人数量相同但 i 小于 j,那么我们认为第 i 行的战斗力比第 j 行弱。军人 总是 排在一行中的靠前位置,也就是说 1 总是出现在 0 之前。

示例 1:

输入:mat = 
[[1,1,0,0,0],
 [1,1,1,1,0],
 [1,0,0,0,0],
 [1,1,0,0,0],
 [1,1,1,1,1]], 
k = 3
输出:[2,0,3]
解释:
每行中的军人数目:
行 0 -> 2 
行 1 -> 4 
行 2 -> 1 
行 3 -> 2 
行 4 -> 5 
从最弱到最强对这些行排序后得到 [2,0,3,1,4]
示例 2:

输入:mat = 
[[1,0,0,0],
 [1,1,1,1],
 [1,0,0,0],
 [1,0,0,0]], 
k = 2
输出:[0,2]
解释: 
每行中的军人数目:
行 0 -> 1 
行 1 -> 4 
行 2 -> 1 
行 3 -> 1 
从最弱到最强对这些行排序后得到 [0,2,3,1]
提示:m == mat.length
n == mat[i].length
2 <= n, m <= 100
1 <= k <= m
matrix[i][j] 不是 0 就是 1

题解

一:二分法+ 排序, 主要看看排序咋写的,排序有两个值, 以1的个数优先,当1的个数相同时看第二个值,及所在行的下标

class Solution(object):
    def kWeakestRows(self, mat, k):
        """
        :type mat: List[List[int]]
        :type k: int
        :rtype: List[int]
        """
        m, n = len(mat), len(mat[0])
        rec = {}

        for i in range(m):
            l, r = 0, n
            while l < r:
                mid = l + (r - l) // 2
                if mat[i][mid] == 1:
                    l = mid + 1
                else:
                    r = mid
            rec[i] = l    
        
        return sorted(range(m), key=lambda x: (rec.get(x), x) )[:k]

268. 缺失数字

https://leetcode-cn.com/problems/missing-number/

给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。

示例 1:输入: [3,0,1],输出: 2
示例 2:输入: [9,6,4,2,3,5,7,0,1],输出: 8
说明:你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现?

题解

一:数学魔法,求和操作缺了谁一目了然

class Solution(object):
    def missingNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        res = 0
        for i in range(len(nums)):
            res ^= i 
            res ^= nums[i]
        res ^= len(nums)
        return res

二:异或操作,记异或魔法

class Solution(object):
    def missingNumber(self, nums):
        ans = 0
        for i, num in enumerate(nums):
            ans ^= i 
            ans ^= num
        ans ^= len(nums)
        return ans 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值