leetcode - c 第 200 场周赛

这次的题都还蛮简单的,大概讲一下做法吧

    1. 统计好三元组

给你一个整数数组 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

给的 arr.length 是 100 我开始还以为是 1000,想了一下觉得 1 0 9 10^9 109 不太能过,又觉得没什么好办法不如硬碰一下暴力做法23333.

  • code
class Solution:
    def countGoodTriplets(self, arr: List[int], a: int, b: int, c: int) -> int:
        n = len(arr)
        ans = 0
        for i in range(n):
            for j in range(i+1,n):
                for k in range(j+1,n):
                    if abs(arr[i]-arr[j])<=a and abs(arr[j]-arr[k])<=b and abs(arr[i]-arr[k])<=c:
                        ans += 1
        return ans
    1. 找出数组游戏的赢家

给你一个由 不同 整数组成的整数数组 arr 和一个整数 k 。

每回合游戏都在数组的前两个元素(即 arr[0] 和 arr[1] )之间进行。比较 arr[0] 与 arr[1]
的大小,较大的整数将会取得这一回合的胜利并保留在位置 0 ,较小的整数移至数组的末尾。当一个整数赢得 k
个连续回合时,游戏结束,该整数就是比赛的 赢家 。

返回赢得比赛的整数。

题目数据 保证 游戏存在赢家。

示例 1:

输入:arr = [2,1,3,5,4,6,7], k = 2 输出:5 解释:一起看一下本场游戏每回合的情况:

因此将进行 4 回合比赛,其中 5 是赢家,因为它连胜 2 回合。

示例 2:

输入:arr = [3,2,1], k = 10 输出:3 解释:3 将会在前 10 个回合中连续获胜。

示例 3:

输入:arr = [1,9,8,2,3,7,6,4,5], k = 7 输出:9

示例 4:

输入:arr = [1,11,22,33,44,55,66,77,88,99], k = 1000000000 输出:99
提示:
2 <= arr.length <= 10^5
1 <= arr[i] <= 10^6
arr 所含的整数 各不相同 。
1 <= k <= 10^9

对题目的直观思路是,如果获胜条件太低,那么可能到不了最大数就能获胜,如果获胜条件高,就肯定是最大数,因此这个问题被压缩进了 1 0 5 10^5 105 。然后本来想着要直接模拟,但很快意识到,如果一个数想要获得胜利,那么必须打败周围的k个人,那么只需要考虑局部最高点即可,“ a z b c d e …… ” ,除了第一个数,每个数都是打败前一个数上位的,那么只需要他比后 k-1 个数大即可,因此得到了遍历做法。

  • code
class Solution:
    def getWinner(self, arr: List[int], k: int) -> int:
        if k >= len(arr)-1:
            return max(arr)
        local = arr[0]
        cnt = 0
        for i in range(1,len(arr)):
            if cnt == k:
                break
            if arr[i]>local:
                local = arr[i]
                cnt = 1
            else:
                cnt += 1
        return local
    1. 排布二进制网格的最少交换次数

给你一个 n x n 的二进制网格 grid,每一次操作中,你可以选择网格的 相邻两行 进行交换。

一个符合要求的网格需要满足主对角线以上的格子全部都是 0 。

请你返回使网格满足要求的最少操作次数,如果无法使网格符合要求,请你返回 -1 。

主对角线指的是从 (1, 1) 到 (n, n) 的这些格子。

示例 1:

输入:grid = [[0,0,1],[1,1,0],[1,0,0]] 输出:3

示例 2:

输入:grid = [[0,1,1,0],[0,1,1,0],[0,1,1,0],[0,1,1,0]] 输出:-1
解释:所有行都是一样的,交换相邻行无法使网格符合要求。

示例 3:

输入:grid = [[1,0,0],[1,1,0],[1,1,1]] 输出:0

提示:

n == grid.length
n == grid[i].length
1 <= n <= 200
grid[i][j] 要么是 0 要么是 1 。

这个题也不是很难,首先统计每一行最后 0 的个数,只要保证找到 最近的 足够多零的 行逐行填充即可。这里需要一点简单的证明:如果第 k 行是最近的能满足第 i 行需求的行,那么前 i+1 到 k-1 行一定拥有更少的 0 ,因此他们满足的行在 i 之后,因此无论如何提前整理这些行都无法规避第 k 行的交换需求,因此可以放心大胆的计算第 k 行的交换次数而无需考虑是否会影响前面 i+1 到 k-1 行的排列情况。

  • code
class Solution:
    def calzero(self, grid):
        n = len(grid)
        zero = [0]*n
        for i in range(n):
            cnt = 0
            for j in range(n-1,0,-1):
                if grid[i][j] == 0:
                    cnt += 1
                else:
                    break
            zero[i] = cnt
        return zero
    def cal(self,a):
        if not a:
            return
        n = len(a)
        for i in range(n):
            if a[i] >= n-1:
                self.ans += i
                self.cal(a[:i]+a[i+1:])
                break
        else:
            self.flag = 1
    def minSwaps(self, grid: List[List[int]]) -> int:
        zero = self.calzero(grid)
        self.ans = 0
        self.flag = 0
        self.cal(zero)
        return -1 if self.flag else self.ans
    1. 最大得分

你有两个 有序 且数组内元素互不相同的数组 nums1 和 nums2 。

一条 合法路径 定义如下:

选择数组 nums1 或者 nums2 开始遍历(从下标 0 处开始)。
从左到右遍历当前数组。
如果你遇到了 nums1 和 nums2 中都存在的值,那么你可以切换路径到另一个数组对应数字处继续遍历(但在合法路径中重复数字只会被统计一次)。

得分定义为合法路径中不同数字的和。

请你返回所有可能合法路径中的最大得分。

由于答案可能很大,请你将它对 10^9 + 7 取余后返回。

示例 1:

输入:nums1 = [2,4,5,8,10], nums2 = [4,6,8,9] 输出:30 解释:合法路径包括:
[2,4,5,8,10], [2,4,5,8,9], [2,4,6,8,9], [2,4,6,8,10],(从 nums1 开始遍历)
[4,6,8,9], [4,5,8,10], [4,5,8,9], [4,6,8,10] (从 nums2 开始遍历)
最大得分为上图中的绿色路径 [2,4,6,8,10] 。

示例 2:

输入:nums1 = [1,3,5,7,9], nums2 = [3,5,100] 输出:109 解释:最大得分由路径
[1,3,5,100] 得到。

示例 3:

输入:nums1 = [1,2,3,4,5], nums2 = [6,7,8,9,10] 输出:40 解释:nums1 和 nums2
之间无相同数字。 最大得分由路径 [6,7,8,9,10] 得到。

示例 4:

输入:nums1 = [1,4,5,8,9,11,19], nums2 = [2,3,4,11,12] 输出:61

提示:

1 <= nums1.length <= 10^5
1 <= nums2.length <= 10^5
1 <= nums1[i], nums2[i] <= 10^7
nums1 和 nums2 都是严格递增的数组。

虽然号称是 Hard 题,但是没有感觉到 Hard 的威力,题目其实非常清楚,按照连接点将链表分段之后,在每个连接点有两个选择,因此只需要贪心选择就够了。问题被分解为几个部分:1.如何用不超时的时间找到连接点:这里用了双指针 O(M+N);2.如何贪心选择:这里直接分段前缀和选最大即可

  • code
class Solution:
	def calnode(self,nums1,nums2):
		i, j = 0, 0
        m, n = len(nums1), len(nums2)
        node = {}
        while i<m and j<n:
            #print(i,j)
            if nums1[i] < nums2[j]:
                i+=1
            elif nums1[i] > nums2[j]:
                j+=1
            else:
                node[i] = j
                i += 1
                j += 1
		return node
	def calsum(self,node,nums1,nums2):
        cnt = 0
        cnt1 = []
        cnt2 = []
        for i in range(m):
            cnt += nums1[i]
            if i in node:
                cnt1.append(cnt)
                cnt = 0
        cnt1.append(cnt)
        cnt = 0
        for i in range(n):
            cnt += nums2[i]
            if i in list(node.values()):
                cnt2.append(cnt)
                cnt = 0
        cnt2.append(cnt)
        return cnt1,cnt2		
    def maxSum(self, nums1: List[int], nums2: List[int]) -> int:
        debug = 0
        mod = 1e9 + 7
        node = self.calnode(nums1,nums2)
        if debug:
            print(node)
        cnt1,cnt2 = self.calsum(node,nums1,nums2)
        if debug:
            print(cnt1,cnt2)
        ans = 0
        for i in range(len(cnt1)):
            ans += max(cnt1[i],cnt2[i])%mod
        return int(ans%mod)

你可能感兴趣的:(leetcode)