LeetCode Cookbook 数组习题(9)终篇

LeetCode Cookbook 数组习题(9) 终篇

   数组部分最后一篇了,这篇内容可能比较水,都是一些简单题,也不知道作者是不是 最后安慰一下 我这刷题小白。

1260. 二维网格迁移

题目链接:1260. 二维网格迁移
题目大意:给你一个 m 行 n 列的二维网格 grid 和一个整数 k。你需要将 grid 迁移 k 次。每次「迁移」操作将会引发下述活动:

  • 位于 grid[i][j] 的元素将会移动到 grid[i][j + 1]。
  • 位于 grid[i][n - 1] 的元素将会移动到 grid[i + 1][0]。
  • 位于 grid[m - 1][n - 1] 的元素将会移动到 grid[0][0]。
  • 请你返回 k 次迁移操作后最终得到的 二维网格。
    在这里插入图片描述

例如:

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

解题思路:按照题意一步一步做有些费劲,需要使用两个 for 循环,计算量少一些不够更加费时,如方法(一),使用贪心找规律计算量稍微大一些,但委实快了许多。

方法(一)

class Solution:
    def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
        # 自己写的 没找规律
        # GF 找规律的想法确实快多了
        m,n = len(grid),len(grid[0])
        if k == 0: return grid
        if m == 1 and n == 1: return grid
        ans = [[0 for _ in range(n)] for _ in range(m)]
        while k > 0:
            ans[0][0] = grid[m-1][n-1]
            if m > 1:
                for i in range(1,m):
                    ans[i][0] = grid[i-1][n-1]
            if n > 1:
                for i in range(m):
                    for j in range(1,n):
                        ans[i][j] = grid[i][j-1]
            grid = [row[:] for row in ans ]
            k -= 1
        return ans

方法(二)

class Solution:
    def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
        m,n = len(grid),len(grid[0])
        ans = [[0] * n for _ in range(m)]
        for i,row in enumerate(grid):
            for j,v in enumerate(row):
                index1 = (i*n + j + k) % (m*n)
                ans[index1 // n][index1 % n] = v
        return ans

1266. 访问所有点的最小时间

题目链接:1266. 访问所有点的最小时间
题目大意:平面上有 n 个点,点的位置用整数坐标表示 points[i] = [xi, yi] 。请你计算访问所有这些点需要的 最小时间(以秒为单位)。你需要按照下面的规则在平面上移动:

  • 每一秒内,你可以:
  • 沿水平方向移动一个单位长度,或者
  • 沿竖直方向移动一个单位长度,或者
  • 跨过对角线移动 sqrt(2) 个单位长度(可以看作在一秒内向水平和竖直方向各移动一个单位长度)。
  • 必须按照数组中出现的顺序来访问这些点。在访问某个点时,可以经过该点后面出现的点,但经过的那些点不算作有效访问。
    在这里插入图片描述

例如:

输入:points = [[1,1],[3,4],[-1,0]]
输出:7
解释:一条最佳的访问路径是: [1,1] -> [2,2] -> [3,3] -> [3,4] -> [2,3] -> [1,2] -> [0,1] -> [-1,0][1,1][3,4] 需要 3 秒 
从 [3,4][-1,0] 需要 4 秒
一共需要 7

解题思路:

  • 贪心,两个点之间 x、y的各自差值绝对值的对比。
class Solution:
    def minTimeToVisitAllPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        x1,y1 = points[0]
        ans = 0
        for i in range(1,n):
            x2,y2 = points[i]
            ans += max(abs(x1-x2),abs(y1-y2))
            x1,y1 = x2,y2
        return ans

1275. 找出井字棋的获胜者

题目链接:1275. 找出井字棋的获胜者
题目大意:AB 在一个 3 x 3 的网格上玩井字棋。井字棋游戏的规则如下:

  • 玩家轮流将棋子放在空方格 (" ") 上。第一个玩家 A 总是用 “X” 作为棋子,而第二个玩家 B 总是用 “O” 作为棋子。“X” 和 “O” 只能放在空方格中,而不能放在已经被占用的方格上。只要有 3 个相同的(非空)棋子排成一条直线(行、列、对角线)时,游戏结束。如果所有方块都放满棋子(不为空),游戏也会结束。游戏结束后,棋子无法再进行任何移动。给你一个数组 moves,其中每个元素是大小为 2 的另一个数组(元素分别对应网格的行和列),它按照 A 和 B 的行动顺序(先 A 后 B)记录了两人各自的棋子位置。
  • 如果游戏存在获胜者(A 或 B),就返回该游戏的获胜者;如果游戏以平局结束,则返回 “Draw”;如果仍会有行动(游戏未结束),则返回 “Pending”。
  • 你可以假设 moves 都 有效(遵循井字棋规则),网格最初是空的,A 将先行动。

例如:

输入:moves = [[0,0],[2,0],[1,1],[2,1],[2,2]]
输出:"A"
解释:"A" 获胜,他总是先走。
"X  "    "X  "    "X  "    "X  "    "X  "
"   " -> "   " -> " X " -> " X " -> " X "
"   "    "O  "    "O  "    "OO "    "OOX"

解题思路:

  • 参考这篇题解写得代码 参考题解
  • 主要思路 看代码了 很清晰了
  • 这里需要备注一点 这里的 itertools.permutations(A,3) 太好用了
from itertools import permutations

class Solution:
    def tictactoe(self, moves: List[List[int]]) -> str:
        if len(moves)<5: return 'Pending'
        A,B = moves[::2],moves[1::2]
        
        for (x1,y1),(x2,y2),(x3,y3) in permutations(A,3):
            if (y2-y1)*(x3-x1) == (y3-y1)*(x2-x1):
                return 'A'

        for (x1,y1),(x2,y2),(x3,y3) in permutations(B,3):
            if (y2-y1)*(x3-x1) == (y3-y1)*(x2-x1):
                return 'B'

        return 'Draw' if len(A)+len(B) == 9 else 'Pending'

1287. 有序数组中出现次数超过25%的元素

题目链接:1287. 有序数组中出现次数超过25%的元素
题目大意:给你一个非递减的 有序 整数数组,已知这个数组中恰好有一个整数,它的出现次数超过数组元素总数的 25%。请你找到并返回这个整数.

例如:

输入:arr = [1,2,2,6,6,6,6,7,10]
输出:6

解题思路: 充分利用 有序数组的性质 即比较 arr[i] == arr[i+n//4]:

(一) 偷懒

class Solution:
    def findSpecialInteger(self, arr: List[int]) -> int:
        
        n = len(arr)
        counter = collections.Counter(arr)
        return counter.most_common()[0][0]

(二) 充分利用 有序数组的性质

class Solution:
    def findSpecialInteger(self, arr: List[int]) -> int:
        
        n = len(arr)
        for i in range(n):
            if arr[i] == arr[i+n//4]:
                return arr[i]
        return -1

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

题目链接:1295. 统计位数为偶数的数字
题目大意: 给你一个整数数组 nums,请你返回其中位数为 偶数 的数字的个数。

例如:

输入:nums = [12,345,2,6,7896]
输出:2
解释:
122 位数字(位数为偶数) 
3453 位数字(位数为奇数)  
21 位数字(位数为奇数) 
61 位数字 位数为奇数) 
78964 位数字(位数为偶数)  
因此只有 127896 是位数为偶数的数字

解题思路: 两种方法 如下:

(一)稍微笨一点的

class Solution:
    def findNumbers(self, nums: List[int]) -> int:
        
        ans = 0
        for num in nums:
            if 9 < num < 100 or 999 < num < 10000 or num == 100000:
                ans += 1
        return ans

(二)转化成字符串长度进行判断

class Solution:
    def findNumbers(self, nums: List[int]) -> int:
        return  sum(1 for num in nums if len(str(num)) % 2 == 0)

1299. 将每个元素替换为右侧最大元素

题目链接:1299. 将每个元素替换为右侧最大元素
题目大意:给你一个数组 arr ,请你将每个元素用它右边最大的元素替换,如果是最后一个元素,用 -1 替换。完成所有替换操作后,请你返回这个数组。

例如:

输入:arr = [17,18,5,4,6,1]
输出:[18,6,6,6,1,-1]
解释:
- 下标 0 的元素 --> 右侧最大元素是下标 1 的元素 (18)
- 下标 1 的元素 --> 右侧最大元素是下标 4 的元素 (6)
- 下标 2 的元素 --> 右侧最大元素是下标 4 的元素 (6)
- 下标 3 的元素 --> 右侧最大元素是下标 4 的元素 (6)
- 下标 4 的元素 --> 右侧最大元素是下标 5 的元素 (1)
- 下标 5 的元素 --> 右侧没有其他元素,替换为 -1

解题思路 :

  • 设置两个变量
  • 逆序遍历 边走边赋值 同时更新最大变量
class Solution:
    def replaceElements(self, arr: List[int]) -> List[int]:
        # 逆序遍历
        n = len(arr)
        j,tmp = -1,0
        for i in range(n-1,-1,-1):
            tmp = arr[i]
            arr[i] = j
            j = max(j,tmp)
        return arr

1300. 转变数组后最接近目标值的数组和 **

题目链接:1300. 转变数组后最接近目标值的数组和
题目大意: 给你一个整数数组 arr 和一个目标值 target ,请你返回一个整数 value ,使得将数组中所有大于 value 的值变成 value 后,数组的和最接近 target (最接近表示两者之差的绝对值最小)。如果有多种使得和最接近 target 的方案,请你返回这些整数中的最小值。

  • 请注意,答案不一定是 arr 中的数字。

例如:

输入:arr = [4,9,3], target = 10
输出:3
解释:当选择 value 为 3 时,数组会变成 [3, 3, 3],和为 9 ,这是最接近 target 的方案。

解题思路: 二分查找 有点难 需要再想想。

class Solution:
    def findBestValue(self, arr: List[int], target: int) -> int:
        low,high = 0,max(arr)
        if sum(arr) <= target: return high

        def check(x: int) -> int:
            res = 0
            for num in arr:
                res += num if num <= x else x
            return res

        def find_smaller(L: int,R: int) -> int:
            while L+1 < R:
                mid = L + (R-L)//2
                if check(mid) <= target:
                    L = mid
                else:
                    R = mid
            return R if check(R) < target else L

        def find_larger(L: int,R: int) -> int:
            while L+1 < R:
                mid = L + (R-L)//2
                if check(mid) >= target:
                    R = mid
                else:
                    L = mid
            return L if check(L) > target else R
            
        
        smaller = find_smaller(low,high)
        larger = find_larger(low,high)
        if abs(target-check(smaller))<=abs(target-check(larger)):
            return smaller
        else:
            return larger

1304. 和为零的 N 个不同整数

题目链接:1304. 和为零的 N 个不同整数
题目大意: 给你一个整数 n,请你返回 任意 一个由 n 个 各不相同 的整数组成的数组,并且这 n 个数相加和为 0

例如:

输入:n = 5
输出:[-7,-1,1,3,4]
解释:这些数组也是正确的 [-5,-1,1,2,3][-3,-1,2,-2,4]

解题思路:简单题 这里提供两种解法

方法(一)

class Solution:
    def sumZero(self, n: int) -> List[int]:
        ans = [x for x in range(1,n)]
        ans.append(-sum(ans))
        return ans

方法(二)

class Solution:
    def sumZero(self, n: int) -> List[int]:
        ans = [x for x in range(1,n)]
        ans.append(-sum(ans))
        return ans

        ans = [i for i in range(1,n//2+1)]
        ans += [-i for i in ans]
        if n % 2 == 0:
            return ans
        else:
            return ans + [0]

1306. 跳跃游戏 III

题目链接:1306. 跳跃游戏 III
题目大意:这里有一个非负整数数组 arr,你最开始位于该数组的起始下标 start 处。当你位于下标 i 处时,你可以跳到 i + arr[i] 或者 i - arr[i]。请你判断自己是否能够跳到对应元素值为 0 的 任一 下标处。注意,不管是什么情况下,你都无法跳到数组之外。

例如:

输入:arr = [4,2,3,0,3,1,2], start = 5
输出:true
解释:到达值为 0 的下标 3 有以下可能方案: 
下标 5 -> 下标 4 -> 下标 1 -> 下标 3 
下标 5 -> 下标 6 -> 下标 4 -> 下标 1 -> 下标 3 

解题思路: 稍微复杂一些 这里仅提供 递归的思路 最好理解了!

class Solution:
    def canReach(self, arr: List[int], start: int) -> bool:
        n  = len(arr)
        if 0<= start <n and arr[start]<n:
            tmp = arr[start]
            if tmp == 0: return True
            # print('tmp',tmp,'start',start)
            arr[start] += n
            return self.canReach(arr,start+tmp) | self.canReach(arr,start-tmp)
        return False

1313. 解压缩编码列表

题目链接:1313. 解压缩编码列表
题目大意:给你一个以行程长度编码压缩的整数列表 nums 。考虑每对相邻的两个元素 [freq, val] = [nums[2i], nums[2i+1]] (其中 i >= 0 ),每一对都表示解压后子列表中有 freq 个值为 val 的元素,你需要从左到右连接所有子列表以生成解压后的列表。请你返回解压后的列表。

例如:

输入:nums = [1,2,3,4]
输出:[2,4,4,4]
解释:
第一对 [1,2] 代表着 2 的出现频次为 1,所以生成数组 [2]。
第二对 [3,4] 代表着 4 的出现频次为 3,所以生成数组 [4,4,4]。
最后将它们串联到一起 [2] + [4,4,4] = [2,4,4,4]

解题思路: 有效的使用 py3 的数组切片功能

class Solution:
    def decompressRLElist(self, nums: List[int]) -> List[int]:
        a,b = nums[::2],nums[1::2]
        ans = []
        for i,j in zip(a,b):
            ans += i*[j]
        return ans

1317. 将整数转换为两个无零整数的和

题目链接:1317. 将整数转换为两个无零整数的和
题目大意:「无零整数」是十进制表示中 不含任何 0 的正整数。给你一个整数 n,请你返回一个 由两个整数组成的列表 [A, B],满足:

  • A 和 B 都是无零整数
  • A + B = n
  • 题目数据保证至少有一个有效的解决方案。如果存在多个有效解决方案,你可以返回其中任意一个。

例如:

输入:n = 2
输出:[1,1]
解释:A = 1, B = 1. A + B = n 并且 A 和 B 的十进制表示形式都不包含任何 0

解题思路: 需要借助 字符串 的功能。

class Solution:
    def getNoZeroIntegers(self, n: int) -> List[int]:
        for L in range(n):
            R = n-L
            if '0' not in str(L) and '0' not in str(R):
                return [L,R]

1380. 矩阵中的幸运数

题目链接:1380. 矩阵中的幸运数
题目大意:给你一个 m * n 的矩阵,矩阵中的数字 各不相同 。请你按 任意 顺序返回矩阵中的所有幸运数。幸运数 是指矩阵中满足同时下列两个条件的元素:

  • 在同一行的所有元素中最小

  • 在同一列的所有元素中最大

    例如:

输入:matrix = 
[[ 3, 7, 8],
 [ 9,11,13],
 [15,16,17]]
输出:[15]
解释:15 是唯一的幸运数,因为它是其所在行中的最小值,也是所在列中的最大值。

解题思路: 幸运数 只有一个 反证法证明

class Solution:
    def luckyNumbers(self, matrix: List[List[int]]) -> List[int]:
        a = max(min(row) for row in matrix)
        b = min(max(col) for col in zip(*matrix))
        return [a] if a==b else []

1385. 两个数组间的距离值

题目链接:1385. 两个数组间的距离值
题目大意:给你两个整数数组 arr1 , arr2 和一个整数 d ,请你返回两个数组之间的 距离值 。

「距离值」 定义为符合此距离要求的元素数目:对于元素 arr1[i] ,不存在任何元素 arr2[j] 满足 |arr1[i]-arr2[j]| <= d 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-the-distance-value-between-two-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

例如:

输入:arr1 = [4,5,8], arr2 = [10,9,1,8], d = 2
输出:2
解释:
对于 arr1[0]=4 我们有:
|4-10|=6 > d=2 |4-9|=5 > d=2 |4-1|=3 > d=2 |4-8|=4 > d=2 
所以 arr1[0]=4 符合距离要求

对于 arr1[1]=5 我们有:
|5-10|=5 > d=2 |5-9|=4 > d=2 |5-1|=4 > d=2 |5-8|=3 > d=2
所以 arr1[1]=5 也符合距离要求

对于 arr1[2]=8 我们有:
|8-10|=2 <= d=2 |8-9|=1 <= d=2 |8-1|=7 > d=2 |8-8|=0 <= d=2
存在距离小于等于 2 的情况,不符合距离要求 

故而只有 arr1[0]=4 和 arr1[1]=5 两个符合距离要求,距离值为 2

解题思路: 二种方法,一种常规做法 双重循环;另一种 巧妙一些 二分法 减少运行时间

方法(一)

class Solution:
    def findTheDistanceValue(self, arr1: List[int], arr2: List[int], d: int) -> int:
        # arr1.sort()
        n = len(arr1)
        ans = 0
        for i in range(n):
            if all(abs(arr1[i]-num)>d for num in arr2) :
                ans += 1 
        return ans

方法(二)

class Solution:
    def findTheDistanceValue(self, arr1: List[int], arr2: List[int], d: int) -> int:
        arr2.sort()
        n = len(arr2)
        ans = 0
        for x in arr1:
            p = bisect.bisect_left(arr2, x)
            if p==n or abs(x-arr2[p])>d:
                if p==0 or abs(x-arr2[p-1])>d:
                    ans += 1
            # if 条件解释
            # if p == n and  abs(x - arr2[p - 1])> d:
            #     ans += 1
            # if p == 0 and abs(x-arr2[p]) > d:
            #     ans += 1
            # if 0< p < n and abs(x-arr2[p]) > d and abs(x-arr2[p-1])>d:
            #     ans += 1
        return ans

1389. 按既定顺序创建目标数组

题目链接:1389. 按既定顺序创建目标数组
题目大意:给你两个整数数组 numsindex。你需要按照以下规则创建目标数组:

  • 目标数组 target 最初为空。
  • 按从左到右的顺序依次读取 nums[i] 和 index[i],在 target 数组中的下标 index[i] 处插入值 nums[i] 。
  • 重复上一步,直到在 nums 和 index 中都没有要读取的元素。
  • 请你返回目标数组,题目保证数字插入位置总是存在。

例如:

输入:nums = [0,1,2,3,4], index = [0,1,2,2,1]
输出:[0,4,1,3,2]
解释:
nums       index     target
0            0        [0]
1            1        [0,1]
2            2        [0,1,2]
3            2        [0,1,3,2]
4            1        [0,4,1,3,2]

解题思路: 充分利用数组切片的功能

class Solution:
    def createTargetArray(self, nums: List[int], index: List[int]) -> List[int]:
        ans = []
        for num,i in zip(nums,index):
            if i >= len(ans):
                ans.append(num)
            else:
                ans = ans[:i] + [num] + ans[i:]
        return ans

1464. 数组中两元素的最大乘积

题目链接:1464. 数组中两元素的最大乘积
题目大意:给你一个整数数组 nums,请你选择数组的两个不同下标 ij,使 (nums[i]-1)*(nums[j]-1) 取得最大值。请你计算并返回该式的最大值。

例如:

输入:nums = [3,4,5,2]
输出:12 
解释:如果选择下标 i=1 和 j=2(下标从 0 开始),则可以获得最大值,(nums[1]-1)*(nums[2]-1) = (4-1)*(5-1) = 3*4 = 12

解题思路: 双指针法 记录 最大值 和 次最大值 当然也可以选择排序直接获取 最大值和次最大值

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 2: return (nums[0]-1)*(nums[1]-1)
        numMax,numSub = nums[0],nums[1] 
        if numMax < numSub: numMax,numSub = numSub,numMax
        for  i in range(2,n):
            num = nums[i]
            if num > numMax:
                numMax,numSub = num,numMax
            elif num > numSub:
                numSub = num
        return (numMax-1)*(numSub-1)

1470. 重新排列数组

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

例如:

输入: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]

解题思路: 充分利用数组切片的功能

class Solution:
    def shuffle(self, nums: List[int], n: int) -> List[int]:
        ans = []
        for i,j in zip(nums[:n],nums[n:]):
            ans += [i,j]
        return ans

总结

  数组,可算弄完了,真累! 收获还是挺大的,线段树是个硬伤啊!必须解决了,它本身变量就有5个,而且代码贼长,与其他的方法结合又十分的让人脑壳疼,不过,我应该可以应付!虽然这次的主题是数组,但字符、动态规划、BFS、DFS、贪心、双指针、二分法、哈希表等都遇到了,只能说学无止境,继续刷题!最后,努力!奋斗!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值