LeetCode:每日一题【第七周】

1608. 特殊数组的特征值【排序】

思路

将数组升序排序,遍历数组,如果nums[n - i] >= i and nums[n - i -1] < i则i满足条件。注意边界情况。

AC代码

class Solution:
    def specialArray(self, nums: List[int]) -> int:
        nums = sorted(nums)
        n = len(nums)
        ans = -1
        for i in range(1, 1001):
            if n - i < 0:
                break
            if nums[n - i] >= i and (n - i == 0 or nums[n - i - 1] < i):
                ans = i
                break
        return ans

这里如果数据量大,也可用二分来找i。但是话说回来,sorted的复杂度已经nlogn了,二分优化不了最大的复杂度,即原来的复杂度是O(nlogn + n),而优化过的复杂度是O(nlogn + logn)。

670. 最大交换【贪心】

思路

先将数的每位分离出来,之后可用交换排序的思想,找数组里面的最大元素,与当前元素做交换。

AC代码

class Solution:
    def maximumSwap(self, num: int) -> int:
        arr = []
        while num > 0:
            arr.append(num % 10)
            num //= 10
        arr = list(reversed(arr))
        n = len(arr)
        # 交换排序
        for i in range(n):
            tmp = arr[i]
            pos = i
            flag = False
            for j in range(n - 1, i, -1):
                if arr[j] > tmp:
                    tmp = arr[j]
                    pos = j
                    flag = True
            arr[i], arr[pos] = arr[pos], arr[i]
            if flag:
                break
        ans = 0
        for val in arr:
            ans = ans * 10 + val
        return ans

1619. 删除某些元素后的数组均值【排序】

思路

最小5%和最大5%就是数组排序后前n/20, 和后n/20的数,将其过滤,算中间数的平均值即可。

AC代码

class Solution:
    def trimMean(self, arr: List[int]) -> float:
        arr = sorted(arr)
        ans, n = 0, len(arr)
        k = n // 20
        for i in range(k, n - k):
            ans += arr[i]
        return ans / (n - k * 2)

672. 灯泡开关 Ⅱ【规律题】

思路

枚举n=1-5的情况,p枚举1-4的情况,会发现答案只有1, 2, 3, 4, 7, 8,这六种答案。

AC代码

class Solution:
    def flipLights(self, n: int, p: int) -> int:
        if p == 0:
            return 1
        if n == 1:
            return 2
        if n == 2:
            return 3 if p == 1 else 4
        if n > 2:
            if p == 1:
                return 4
            return 7 if p == 2 else 8

850. 矩形面积 II

不会,这题用了好几种算法
换个题吧

1856.子数组最小乘积的最大值【前缀和+单调栈】

思路

  • 找右边第一个比当前值小的下标r, 再找左边第一个比当前值小的下标l,求这段区间的和
  • 这段区间的和可以用前缀和预处理
  • 找l 和 r用单调栈

AC代码

class Solution:
    def maxSumMinProduct(self, nums: List[int]) -> int:
        nums = [0] + nums + [0]  # 添加两个哨兵作为单调栈的两个边界
        pre_sum = [0]
        for num in nums:
            pre_sum.append(pre_sum[-1] + num)
        
        n = len(nums)
        rfs = [None] * n  # right_first_smaller 找右边第一个比i小的
        stack = []
        for i in range(n):
            while stack and nums[i] < nums[stack[-1]]:
                rfs[stack.pop()] = i
            stack.append(i)

        lfs = [None] * n  # left_first_smaller 找左边第一个比i小的
        stack = []
        for i in range(n - 1, -1, -1):
            while stack and nums[i] < nums[stack[-1]]:
                lfs[stack.pop()] = i
            stack.append(i)
        
        mx = 0
        for i in range(1, n - 1):
            r = rfs[i]
            l = lfs[i]
            mx = max(mx, nums[i] * (pre_sum[r] - pre_sum[l + 1]))
        return mx % (10**9 + 7)

1624. 两个相同字符之间的最长子字符串

思路

用字符映射,只存不同字符出现的第一个字符,然后判断后面字符串有相同字符,将其下标作差-1即可。

AC代码

class Solution:
    def maxLengthBetweenEqualCharacters(self, s: str) -> int:
        tmp = [None] * 26
        ans = -1
        for i, ch in enumerate(s):
            if tmp[ord(ch) - 97] != None:
                ans = max(ans, i - tmp[ord(ch) - 97] - 1)
            else:
                tmp[ord(ch) - 97] = i
        return ans 

827. 最大人工岛【并查集】

思路

第一遍并查集:将所有连通的1合并的一个集合
第二遍并查集:判断当前值为0的周边值,如果为1,则可将0变成1再来看连通分量的大小是多少。

AC代码

class Solution:
    # 方法1并查集
    def largestIsland(self, grid: List[List[int]]) -> int:
        def find(a):
            if f[a] != a:
                f[a] = find(f[a])
            return f[a]
        def union(a, b):
            fa, fb = find(a), find(b)
            if fa != fb:
                f[fa] = fb # fb为父亲
                size[fb] += size[fa]

        n = len(grid)
        f = list(range(n * n))
        size = [1] * (n * n)

        for i, row in enumerate(grid):
            for j, v in enumerate(row):
                if v == 1: # 将连通的1合并为一个集合
                    for a, b in [[0, -1], [-1, 0]]: # python强大之处,不用遍历四个方向,因为左边界走完就到了右边界,上边界走完到了下边界。
                        x, y = i + a, j + b
                        if 0 <= x < n and 0 <= y < n and grid[x][y] == 1:
                            union(x * n + y, i * n + j) # 将其转化为1维进行合并

        ans = max(size)
        for i, row in enumerate(grid):
            for j, v in enumerate(row):
                vis = set()
                t = 1
                if v == 0:
                    for a, b in [[0, -1], [-1, 0], [0, 1], [1, 0]]:
                        x, y = i + a, j + b
                        if 0 <= x < n and 0 <= y < n and grid[x][y] == 1:
                            root = find(x * n + y)
                            if root not in vis:
                                vis.add(root)
                                t += size[root] # 累加周围连通块为1的集合大小
                ans = max(ans, t)
        return ans

你可能感兴趣的:(算法刷题库,leetcode,算法,职场和发展)