CodeTop整理-数组篇

目录

53. 最大子序和

33. 搜索旋转排序数组

三数之和

121. 买卖股票的最佳时机

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

695. 岛屿的最大面积

54. 螺旋矩阵

88. 合并两个有序数组

152. 乘积最大子数组

42. 接雨水

64. 最小路径和

1. 两数之和

123. 买卖股票的最佳时机 III

48. 旋转图像

34. 在排序数组中查找元素的第一个和最后一个位置

31. 下一个排列

85. 最大矩形

560. 和为K的子数组

56. 合并区间

45. 跳跃游戏 II

84. 柱状图中最大的矩形

128. 最长连续序列

122. 买卖股票的最佳时机 II

62. 不同路径

11. 盛最多水的容器

41. 缺失的第一个正数

39. 组合总和

611. 有效三角形的个数

55. 跳跃游戏

105. 从前序与中序遍历序列构造二叉树

169. 多数元素

209. 长度最小的子数组

162. 寻找峰值

74. 搜索二维矩阵

40. 组合总和 II

1031. 两个非重叠子数组的最大和

73. 矩阵置零

剑指 Offer 29. 顺时针打印矩阵

78. 子集

面试题 10.03. 搜索旋转数组

153. 寻找旋转排序数组中的最小值

509. 斐波那契数

287. 寻找重复数

718. 最长重复子数组

189. 轮转数组

167. 两数之和 II - 输入有序数组

238. 除自身以外数组的乘积

79. 单词搜索

剑指 Offer 04. 二维数组中的查找

670. 最大交换

75. 颜色分类

581. 最短无序连续子数组

剑指 Offer 53 - I. 在排序数组中查找数字 I

442. 数组中重复的数据

380. O(1) 时间插入、删除和获取随机元素

26. 删除排序数组中的重复项

面试题 16.16. 部分排序

16. 最接近的三数之和

1208. 尽可能使字符串相等

1122. 数组的相对排序

57. 插入区间

18. 四数之和

1539. 第 k 个缺失的正整数

268. 缺失数字


53. 最大子序和
# 53. 最大子数组和
# 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
# 子数组 是数组中的一个连续部分。
# 输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
# 输出:6
# 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

class Solution:
    # def maxSubArray(self, nums: List[int]) -> int:
    def maxSubArray(self, nums):
        dp=nums
        for i in range(1,len(nums)):
            dp[i]=max(dp[i-1]+nums[i],nums[i])
        return max(dp)

33. 搜索旋转排序数组
# 33. 搜索旋转排序数组
# 整数数组 nums 按升序排列,数组中的值 互不相同 。
# 在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为[4,5,6,7,0,1,2] 。
# 给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回-1。
# 你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
#
# 输入:nums = [4,5,6,7,0,1,2], target = 0
# 输出:4
class Solution:
    # def search(self, nums: List[int], target: int) -> int:
    def search(self, nums, target) :
        n=len(nums)
        l,r=0,n-1
        while(l<r):
            m=(l+r)//2
            if(nums[-1]>=nums[m]):
                r=m
            else:
                l=m+1
        if(target>nums[-1]):
            l,r=0,l
        else:
            l, r = l, n-1

        while(l<r):
            m=(l+r)//2
            if(nums[m]>=target):
                r=m
            else:
                l=m+1
        ans=-1
        if(nums[l]==target):
            ans=l
        return ans

三数之和
# 15. 三数之和
# 给你一个包含 n 个整数的数组nums,判断nums中是否存在三个元素 a,b,c ,使得a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
# 注意:答案中不可以包含重复的三元组
# 输入:nums = [-1,0,1,2,-1,-4]
# 输出:[[-1,-1,2],[-1,0,1]]

class Solution:
    # def threeSum(self, nums: List[int]) -> List[List[int]]:
    def threeSum(self, nums):
        nums.sort()
        n=len(nums)
        ans=[]
        for i in range(n-2):
            if i>0 and nums[i-1]==nums[i]:
                continue
            if nums[i]+nums[i+1]+nums[i+2]>0:
                break
            if nums[i]+nums[n-1]+nums[n-2]<0:
                continue
            l,r=i+1,n-1
            while(l<r):
                total=nums[i]+nums[l]+nums[r]
                if(total==0):
                    ans.append([nums[i],nums[l],nums[r]])
                    while(l<r and nums[l+1]==nums[l]):
                        l+=1
                    l+=1
                    while(l<r and nums[r-1]==nums[r]):
                        r-=1
                    r-=1
                elif(total<0):
                    l+=1
                else:
                    r-=1
        return ans

s=Solution()
# nums = [-1,0,1,2,-1,-4]
nums=[-2,0,0,2,2]
r=s.threeSum(nums)
print(r)
121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        dp=[0]*len(prices)
        min_i=0
        for i in range(1,len(prices)):
            if(prices[min_i]>prices[i]):
                min_i=i
            if(min_i!=i):
                dp[i]=prices[i]-prices[min_i]
        return max(dp)
4. 寻找两个正序数组的中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

#https://leetcode.cn/problems/median-of-two-sorted-arrays/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-2/
# 输入:nums1 = [1,3], nums2 = [2]
# 输出:2.00000
# 解释:合并数组 = [1,2,3] ,中位数 2
class Solution:
    # def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
    def findMedianSortedArrays(self, nums1, nums2):
        m=len(nums1)
        n=len(nums2)
        if(m>n):
            return self.findMedianSortedArrays(nums2,nums1)
        print(m,n)
        min_i,max_i=0,m
        while(min_i<=max_i):
            i=(min_i+max_i)//2
            j=(m+n+1)//2-i
            # print("i,j",i,j)
            if(i>0  and j<n and nums1[i-1]>nums2[j]):
                max_i-=1
            elif(j>0 and i<m  and nums2[j-1]>nums1[i]):
                min_i+=1
            else:
                max_left=0
                if(i==0):
                    max_left=nums2[j-1]
                elif(j==0):
                    max_left=nums1[i-1]
                else:
                    max_left=max(nums1[i-1],nums2[j-1])
                if(m+n)%2==1:
                    return max_left

                min_right=0
                if(i==m):
                    min_right=nums2[j]
                elif(j==n):
                    min_right=nums1[i]
                else:
                    min_right=min(nums1[i],nums2[j])
                if((m+n)%2)==0:
                    return  (max_left+min_right)/2
        return 0.0
s=Solution()
# nums1 = [1,3]
# nums2 = [2]
# nums1=[]
# nums2=[1]
nums1=[2]
nums2=[]
r=s.findMedianSortedArrays(nums1,nums2)
print(r)

695. 岛屿的最大面积
# 给你一个大小为 m x n 的二进制矩阵 grid 。
# 岛屿是由一些相邻的1(代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设grid 的四个边缘都被 0(代表水)包围着。
# 岛屿的面积是岛上值为 1 的单元格的数目。
#
# 计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0
# 输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
# 输出:6
# 解释:答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1 。

class Solution:
    # def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
    def maxAreaOfIsland(self, grid):
        def dfs(i,j):
            area=0
            if  i>=0 and i<len(grid) and j>=0 and j<len(grid[0]) and grid[i][j] and not flag[i][j]:
                flag[i][j]=True
                area=dfs(i-1,j)+dfs(i+1,j)+dfs(i,j-1)+dfs(i,j+1)+grid[i][j]
            return area

        ans=0
        flag=[[False]*len(grid[0]) for i in range(len(grid))]

        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if(grid[i][j]==1):
                    area=dfs(i,j)
                    ans=max(area,ans)
        return ans

s=Solution()
grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
r=s.maxAreaOfIsland(grid)
print(r)

54. 螺旋矩阵
# 54. 螺旋矩阵
# 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
# 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
# 输出:[1,2,3,6,9,8,7,4,5]

class Solution:
    # def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
    def spiralOrder(self, matrix) :
        m,n=len(matrix),len(matrix[0])
        t,b,l,r=0,m-1,0,n-1
        ans=[]
        while(t<=b and l<=r):
            for i in range(l,r+1): #上
                ans.append(matrix[t][i])
            t+=1
            for i in range(t,b+1):  #右
                ans.append(matrix[i][r])
            r-=1
            if(l<=r and t<=b):            #上、右均变化,防止重复计算
                for i in range(r,l-1,-1): #下
                    ans.append(matrix[b][i])
                b-=1
                for i in range(b,t-1,-1): #左
                    ans.append(matrix[i][l])
                l+=1
        return ans

s=Solution()
matrix = [[1,2,3],[4,5,6],[7,8,9]]
r=s.spiralOrder(matrix)
print(r)

88. 合并两个有序数组
# 88. 合并两个有序数组
# 给你两个按 非递减顺序 排列的整数数组nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
#
# 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
#
# 注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
#
# 输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
# 输出:[1,2,2,3,5,6]
# 解释:需要合并 [1,2,3] 和 [2,5,6] 。
# 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。


class Solution:
    # def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
    #     """
    #     Do not return anything, modify nums1 in-place instead.
    #     """

    def merge(self, nums1, m, nums2, n):
        i,j,k=m-1,n-1,m+n-1

        while i>=0 and j>=0:
            if(nums1[i]>nums2[j]):
                nums1[k]=nums1[i]
                i-=1
            else:
                nums1[k]=nums2[j]
                j-=1
            k-=1

        while i>=0:
            nums1[k]=nums1[i]
            k-=1
            i-=1
        while j>=0:
            nums1[k]=nums2[j]
            k-=1
            j-=1

# nums1 = [1,2,3,0,0,0]
# m = 3
# nums2 = [2,5,6]
# n = 3

nums1=[0]
m=0
nums2=[1]
n=1
s=Solution()
s.merge(nums1,m,nums2,n)
print(nums1)

152. 乘积最大子数组
# 152. 乘积最大子数组
# 给你一个整数数组 nums,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
# 测试用例的答案是一个32-位 整数。
#
# 子数组 是数组的连续子序列。
# 输入: nums = [2,3,-2,4]
# 输出: 6
# 解释: 子数组 [2,3] 有最大乘积 6。

class Solution:
    # def maxProduct(self, nums: List[int]) -> int:
    def maxProduct(self, nums) :
        dp_min=[0]*len(nums)
        dp_max=[0]*len(nums)
        dp_max[0]=dp_min[0]=nums[0]
        for i in range(1,len(nums)):
            dp_min[i]=min(dp_max[i-1]*nums[i],dp_min[i-1]*nums[i],nums[i])
            dp_max[i] = max(dp_max[i - 1] * nums[i], dp_min[i - 1] * nums[i], nums[i])
        return max(dp_max)

# class Solution:
#     def maxProduct(self, nums: List[int]) -> int:
#         if not nums:
#             return 0
#         max_pro,min_pro,min_cur,max_cur=nums[0],nums[0],nums[0],nums[0]
#         for i in range(1,len(nums)):
#             min_cur,max_cur=min(min(nums[i],min_cur*nums[i]),max_cur*nums[i]),max(min_cur*nums[i],max(max_cur*nums[i],nums[i]))
#             if(max_pro<max_cur):
#                 max_pro=max_cur
#             if(min_pro>min_cur):
#                 min_pro=min_cur
#         print("min_pro:",min_pro)
#         print("max_pro:",max_pro)
#         return max_pro

s=Solution()
# nums=[2,3,-2,4]
nums=[-2,3,-4]
r=s.maxProduct(nums)
print(r)

42. 接雨水
# 42. 接雨水
# 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
# 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
# 输出:6
# 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
class Solution:
    # def trap(self, height: List[int]) -> int:
    def trap(self, height):
        left=[0]*len(height)
        right=[0]*len(height)
        left[0]=height[0]
        right[-1]=height[-1]

        for i in range(1,len(height)):
            left[i]=max(left[i-1],height[i])
        for i in range(len(height)-2,-1,-1):
            right[i]=max(right[i+1],height[i])
        ans=0
        for i in range(len(height)):
            ans+=min(left[i],right[i])-height[i]
        return ans

64. 最小路径和
# 64. 最小路径和
# 给定一个包含非负整数的 mxn网格grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
# 说明:每次只能向下或者向右移动一步。
# 输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
# 输出:7
# 解释:因为路径 1→3→1→1→1 的总和最小。


class Solution:
    # def minPathSum(self, grid: List[List[int]]) -> int:
    def minPathSum(self, grid):
        dp=[[0]*len(grid[0]) for i in range(len(grid))]
        dp[0][0]=grid[0][0]
        for i in range(1,len(grid)):
           dp[i][0]=grid[i][0]+dp[i-1][0]

        for i in range(1,len(grid[0])):
            dp[0][i]=grid[0][i]+dp[0][i-1]

        for i in range(1,len(grid)):
            for j in range(1,len(grid[0])):
                dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j]
        return dp[-1][-1]

grid = [[1,3,1],[1,5,1],[4,2,1]]
s=Solution()
r=s.minPathSum(grid)
print(r)
1. 两数之和
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        h={}
        for i,num in enumerate(nums) :
            if target-num in h:
                return [h[target-num],i]
            h[num]=i
        return [-1,-1]
123. 买卖股票的最佳时机 III
# 123. 买卖股票的最佳时机 III
# 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
# 设计一个算法来计算你所能获取的最大利润。你最多可以完成两笔交易。
# 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
#
# 输入:prices = [3,3,5,0,0,3,1,4]
# 输出:6
# 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
#     随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。


class Solution:
    # def maxProfit(self, prices: List[int]) -> int:
    def maxProfit(self, prices):
        left=[0]*len(prices)
        left_min=prices[0]
        right=[0]*len(prices)

        for i in range(1,len(prices)):
            left_min=min(prices[i],left_min)
            left[i]=prices[i]-left_min

        right_max=prices[-1]
        for i in range(len(prices)-2,0,-1):
            right[i]=right_max-prices[i+1]
            right_max = max(prices[i], right_max)
            right[i]=max(right[i],right[i+1])

        ans=max(left)
        # print(prices)
        # print(left)
        # print(right)
        for i in range(len(prices)):
            ans=max(left[i]+right[i],ans)

        return ans

s=Solution()
prices = [3,3,5,0,0,3,1,4]
r=s.maxProfit(prices)
print(r)
48. 旋转图像
# 48. 旋转图像
# 给定一个 n×n 的二维矩阵matrix 表示一个图像。请你将图像顺时针旋转 90 度。
# 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
# 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
# 输出:[[7,4,1],[8,5,2],[9,6,3]]


# class Solution:
#
#     def rotate(self, matrix: List[List[int]]) -> None:
#         """
#         Do not return anything, modify matrix in-place instead.
#         """
#
#         r_s = 0  # 行开始
#         r_e = len(matrix) - 1  # 行结束
#         c_s = 0  # 列开始
#         c_e = len(matrix[0]) - 1  # 列结束
#         n = len(matrix)
#
#         while (r_s < r_e):
#             for i in range(c_s, c_e):
#                 '''
#                 从外至内,顺方向替换,各个位置的变换关系如下所示
#                 matrix[r_s][i]->matrix[i][c_e]
#                 matrix[i][c_e]->matrix[r_e][n-i-1]
#                 matrix[r_e][n-i-1]->matrix[n-i-1][c_s]
#                 matraix[n-i-1][c_s]->matraix[r_s][i]
#                 '''
#
#                 t = matrix[r_s][i]
#                 matrix[r_s][i] = matrix[n - i - 1][c_s]
#                 matrix[n - i - 1][c_s] = matrix[r_e][n - i - 1]
#                 matrix[r_e][n - i - 1] = matrix[i][c_e]
#                 matrix[i][c_e] = t
#
#             r_s += 1
#             r_e -= 1
#             c_s += 1
#             c_e -= 1

class Solution:
    # def rotate(self, matrix: List[List[int]]) -> None:
    def rotate(self, matrix):

        """
        Do not return anything, modify matrix in-place instead.
        """
        t,b,l,r,m,n=0,len(matrix)-1,0,len(matrix[0])-1,len(matrix)-1,len(matrix[0])-1
        while(t<b):
            for k in range(l,r):
                # print(t,b,l,r)
                # print('(',t,k,')','(',m-k,l,')','(',b,n-k,')','(',k,r,')')
                # print(matrix[t][k],matrix[m-k][l],matrix[b][n-k],matrix[k][r])
                tmp=matrix[t][k]
                matrix[t][k]=matrix[m-k][l]
                matrix[m-k][l]=matrix[b][n-k]
                matrix[b][n-k]=matrix[k][r]
                matrix[k][r]=tmp
                # print( matrix[t][k],matrix[m-k][l],matrix[b][n-k],matrix[k][r])

            t+=1
            b-=1
            l+=1
            r-=1

matrix = [[1,2,3],[4,5,6],[7,8,9]]
s=Solution()
print(matrix)
r=s.rotate(matrix)
print(matrix)
34. 在排序数组中查找元素的第一个和最后一个位置
# 34. 在排序数组中查找元素的第一个和最后一个位置
# 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
# 如果数组中不存在目标值 target,返回[-1, -1]。
# 你必须设计并实现时间复杂度为O(log n)的算法解决此问题。
# 输入:nums = [5,7,7,8,8,10], target = 8
# 输出:[3,4]

class Solution:
    # def searchRange(self, nums: List[int], target: int) -> List[int]:
    def searchRange(self, nums, target) :
        if not nums:
            return [-1,-1]
        ans=[-1,-1]
        l,r=0,len(nums)-1
        while(l<r):
            m=(l+r)//2
            print("1:",l,r,m, nums[m])
            if(nums[m]>=target):
                r=m
            else:
                l=m+1
        if(l<len(nums) and nums[l]!=target):
            return ans
        else:
            ans[0]=l

        l, r = 0, len(nums) - 1
        while(l<r):
            m=(l+r+1)//2
            print("2:",l,r,m, nums[m])
            if(nums[m]<=target):
                l=m
            else:
                r=m-1
        if (l<len(nums) and nums[l] != target):
            return [-1,-1]
        else:
            ans[1] = l
        return ans

s=Solution()
# nums = [5,7,7,8,8,10]
# target = 8
nums =[]
target =0
r=s.searchRange(nums,target)
print(r)
31. 下一个排列
# 31. 下一个排列
# 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
#
# 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
# 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
#
# 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
# 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
# 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
# 给你一个整数数组 nums ,找出 nums 的下一个排列。
#
# 必须 原地 修改,只允许使用额外常数空间。
# 输入:nums = [1,2,3]
# 输出:[1,3,2]
# https://leetcode.cn/problems/next-permutation/solution/fen-6bu-fen-xi-si-lu-qing-xi-ji-bai-9982-pwr5/ 这个解析较为详细

class Solution:
    # def nextPermutation(self, nums: List[int]) -> None:
    #     """
    #     Do not return anything, modify nums in-place instead.
    #     """

    def nextPermutation(self, nums) :

        i=len(nums)-1
        while(i>0 and nums[i-1]>=nums[i]): #找到反向第一对顺序下标
            i-=1

        if(i>0):              #i-1为反向第一对顺下较小数的下标,当==0时,说明整个序列为降序,为最大排序,直接反转即可
            j=len(nums)-1
            while(j>i-1 and nums[j]<=nums[i-1]):  #找到反向第一个大于nums[i]的下标
                j-=1
            nums[i-1],nums[j]=nums[j],nums[i-1]

        print(i-1,j)
        l,r=i,len(nums)-1
        while(l<r):                       #i到len(nums)为反向降序排列,即最大的排序序列,反转将其变为最小的序列
            nums[l],nums[r]=nums[r],nums[l]
            l+=1
            r-=1

s=Solution()
arr = [1,2,3]
r=s.nextPermutation(arr)
print(arr)
85. 最大矩形
class Solution:
    # def maximalRectangle(self, matrix: List[List[str]]) -> int:
    def maximalRectangle(self, matrix):
        m,n=len(matrix),len(matrix[0])
        pillar=[[0]*len(matrix[0]) for i in range(len(matrix))]
        for i in range(m):
            for j in range(n):
                if matrix[i][j]=='1':
                    if i==0:
                        pillar[i][j]=1
                    else:
                        pillar[i][j]=pillar[i-1][j]+1

        res=0
        for i in range(m):
            # 柱形的最大面积求法,84题
            area_i=0
            left,right=[0]*n,[0]*n
            cur_min=[]
            for j in range(n):
                while cur_min and pillar[i][j]<=pillar[i][cur_min[-1]]:
                    cur_min.pop()
                if cur_min:
                    left[j]=cur_min[-1]
                else:
                    left[j]=-1
                cur_min.append(j)

            cur_min=[]
            for j in range(n-1,-1,-1):
                while cur_min and pillar[i][j]<=pillar[i][cur_min[-1]]:
                    cur_min.pop()
                if cur_min:
                    right[j]=cur_min[-1]
                else:
                    right[j]=n
                cur_min.append(j)

            for j in range(n):
                area_i=max(area_i,(right[j]-left[j]-1)*pillar[i][j])
            res=max(res,area_i)

        return res

560. 和为K的子数组

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 

输入:nums = [1,1,1], k = 2
输出:2
class Solution:
    # def subarraySum(self, nums: List[int], k: int) -> int:
    def subarraySum(self, nums, k) :
        from collections import defaultdict
        res=0
        n=len(nums)
        h=defaultdict(int)
        pre_sum=0
        h[0]=1

        for i in range(n):
            pre_sum+=nums[i]
            if (pre_sum-k) in h:
                res+=h[pre_sum-k]
            h[pre_sum]=h[pre_sum]+1
        return res

56. 合并区间
# 56. 合并区间
# 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间
# 输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
# 输出:[[1,6],[8,10],[15,18]]
# 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].


class Solution:
    # def merge(self, intervals: List[List[int]]) -> List[List[int]]:
    def merge(self, intervals) :
        intervals.sort(key=lambda x:x[0])
        res=[intervals[0]]
        for i in range(1,len(intervals)):
            if res[-1][1]>=intervals[i][0]:
                res[-1][1]=max(res[-1][1],intervals[i][1])
            else:
                res.append(intervals[i])
        return res

intervals = [[1,3],[2,6],[8,10],[15,18]]
s=Solution()
r=s.merge(intervals)
print(r)

45. 跳跃游戏 II
# 45. 跳跃游戏 II
# 给你一个非负整数数组nums ,你最初位于数组的第一个位置。
# 数组中的每个元素代表你在该位置可以跳跃的最大长度。
# 你的目标是使用最少的跳跃次数到达数组的最后一个位置。
# 假设你总是可以到达数组的最后一个位置。
#
# 输入: nums = [2,3,1,1,4]
# 输出: 2
# 解释: 跳到最后一个位置的最小跳跃数是 2。
#     从下标为 0 跳到下标为 1 的位置,跳1步,然后跳3步到达数组的最后一个位置。

# 在具体的实现中,我们维护当前能够到达的最大下标位置,记为边界。我们从左到右遍历数组,到达边界时,更新边界并将跳跃次数增加 1。
# 在遍历数组时,我们不访问最后一个元素,这是因为在访问最后一个元素之前,我们的边界一定大于等于最后一个位置,否则就无法跳到最后一个位置了。如果访问最后一个元素,在边界正好为最后一个位置的情况下,我们会增加一次「不必要的跳跃次数」,因此我们不必访问最后一个元素。


# 正向最大可达,上一次跳跃结束时,进行计数,避免无效的计数
class Solution:
    # def jump(self, nums: List[int]) -> int:
    def jump(self, nums) :
        cnt=0
        max_jump=0
        last_jump=0
        for i in range(len(nums)-1):
            if(i<=max_jump):
                max_jump=max(max_jump,nums[i]+i)
                if (i==last_jump):           # 1-nums[i]遍历完了,并且找到这个区间内最优的跳跃方式
                    cnt+=1
                    last_jump=max_jump
        return cnt

# nums = [2,3,1,1,4]
nums =[7,0,9,6,9,6,1,7,9,0,1,2,9,0,3]
s=Solution()
r=s.jump(nums)
print(r)

84. 柱状图中最大的矩形
# 84. 柱状图中最大的矩形
# 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
# 求在该柱状图中,能够勾勒出来的矩形的最大面积。
# 输入:heights = [2,1,5,6,2,3]
# 输出:10
# 解释:最大的矩形为图中红色区域,面积为 10

class Solution:
    # def largestRectangleArea(self, heights: List[int]) -> int:
    def largestRectangleArea(self, heights) :
        left=[0]*len(heights)
        right=[0]*len(heights)
        st=[]
        for i in range(len(heights)):
            while st and heights[i]<=heights[st[-1]]:    #left[i]记录第一个比height[i]大的下标
                st.pop()
            if st:
                left[i]=(st[-1])
            else:
                left[i]=-1
            st.append(i)

        st=[]
        for i in range(len(heights)-1,-1,-1):
            while st and heights[i]<=heights[st[-1]]:  #right[i]记录第一个比height[i]大的下标
                st.pop()
            if st:
                right[i]=st[-1]
            else:
                right[i]=len(heights)
            st.append(i)

        # print(heights)
        # print(left)
        # print(right)

        area=0
        for i in range(len(heights)):
            area=max(area,(right[i]-left[i]-1)*heights[i])  #left[i]满足height[i]最小的前一个下标, right[i]满足height[i]最小的后一个下标
        return area

s=Solution()
heights = [2,1,5,6,2,3]
r=s.largestRectangleArea(heights)
print(r)

128. 最长连续序列
# 128. 最长连续序列
# 给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
# 请你设计并实现时间复杂度为O(n) 的算法解决此问题。
# 输入:nums = [100,4,200,1,3,2]
# 输出:4
# 解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。


class Solution:
    # def longestConsecutive(self, nums: List[int]) -> int:
    def longestConsecutive(self, nums) :
        num_dict={}
        for num in nums:
            num_dict[num]=1
        ans=0
        for num in nums:
            num=num
            if num-1 not in num_dict:   #不重复计算已经判断过的连续子串
                k=1
                num+=1
                while(num in num_dict):
                    k+=1
                    num+=1
                ans=max(ans,k)
                k=0
        return ans
122. 买卖股票的最佳时机 II
# 122. 买卖股票的最佳时机 II
# 给你一个整数数组 prices ,其中prices[i] 表示某支股票第 i 天的价格。
#
# 在每一天,你可以决定是否购买和/或出售股票。你在任何时候最多只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
#
# 返回 你能获得的 最大 利润。
# 输入:prices = [7,1,5,3,6,4]
# 输出:7
# 解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
#     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
#      总利润为 4 + 3 = 7 。

class Solution:
    # def maxProfit(self, prices: List[int]) -> int:
    def maxProfit(self, prices) :
        ans=0
        for i in range(1,len(prices)):
            ans+=max(0,prices[i]-prices[i-1])
        return ans

s=Solution()
prices = [7,1,5,3,6,4]
r=s.maxProfit(prices)
print(r)

62. 不同路径
# 62. 不同路径
# 一个机器人位于一个 m x n网格的左上角 (起始点在下图中标记为 “Start” )。
# 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
# 问总共有多少条不同的路径?
# 输入:m = 3, n = 7
# 输出:28

class Solution:
    # def uniquePaths(self, m: int, n: int) -> int:
    def uniquePaths(self, m, n) :
        dp=[[0]*n for i in range(m)]
        for i in range(m):
            dp[i][0]=1
        for j in range(n):
            dp[0][j]=1

        for i in range(1,m):
            for j in range(1,n):
                dp[i][j]=dp[i-1][j]+dp[i][j-1]

        return dp[-1][-1]

m,n=3,7
s=Solution()
r=s.uniquePaths(m,n)
print(r)
11. 盛最多水的容器
# 11. 盛最多水的容器
# 给定一个长度为 n 的整数数组height。有n条垂线,第 i 条线的两个端点是(i, 0)和(i, height[i])。
# 找出其中的两条线,使得它们与x轴共同构成的容器可以容纳最多的水。
#
# 返回容器可以储存的最大水量。
#
# 说明:你不能倾斜容器。
# 输入:[1,8,6,2,5,4,8,3,7]
# 输出:49
# 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为49。

class Solution:
    # def maxArea(self, height: List[int]) -> int:
    def maxArea(self, height) :
        l,r=0,len(height)-1
        area=0
        while(l<r):
            t=min(height[l],height[r])*(r-l)
            area=max(area,t)
            if height[l]<height[r]:
                l+=1
            else:
                r-=1
        return area



s=Solution()
# heights=[1,8,6,2,5,4,8,3,7]
# heights=[1,1]
heights=[1,2,1]
r=s.maxArea(heights)
print(r)
41. 缺失的第一个正数
# 41. 缺失的第一个正数
# 给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
# 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

# 输入:nums = [1,2,0]
# 输出:3

class Solution:
    # def firstMissingPositive(self, nums: List[int]) -> int:
    def firstMissingPositive(self, nums):
        for i in range(len(nums)):
            while nums[i]>0 and nums[i]<=len(nums) and nums[nums[i]-1]!=nums[i]:
                t=nums[nums[i]-1]
                nums[nums[i]-1]=nums[i]
                nums[i]=t
        # print(nums)
        k=0
        while k<len(nums):
            if k+1!=nums[k]:
                return k+1
            k+=1
        return k+1
39. 组合总和
# 39. 组合总和
# 给你一个 无重复元素 的整数数组candidates 和一个目标整数target,找出candidates中可以使数字和为目标数target 的 所有不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
#
# candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
#
# 对于给定的输入,保证和为target 的不同组合数少于 150 个。
# 输入:candidates = [2,3,6,7], target = 7
# 输出:[[2,2,3],[7]]
# 解释:
# 2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
# 7 也是一个候选, 7 = 7 。
# 仅有这两种组合。

class Solution:
    # def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
    def combinationSum(self, candidates, target):
        ans=[]
        def dfs(s,target,t):
            if target==0:
                ans.append(t)
            if target<0:
                return

            for i in range(s,len(candidates)):
                if i>0 and candidates[i-1]==candidates[i]:
                    continue
                dfs(i,target-candidates[i],t+[candidates[i]])
        dfs(0,target,[])
        return ans
s=Solution()
candidates = [2,3,6,7]
target = 7
r=s.combinationSum(candidates,target)
print(r)
611. 有效三角形的个数
# 611. 有效三角形的个数
# 给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。
# 输入: nums = [2,2,3,4]
# 输出: 3
# 解释:有效的组合是:
# 2,3,4 (使用第一个 2)
# 2,3,4 (使用第二个 2)
# 2,2,3

class Solution:
    # def triangleNumber(self, nums: List[int]) -> int:
    def triangleNumber(self, nums) :
        nums.sort()
        n=len(nums)
        ans=0
        for i in range(n):
            l,r=0,i-1
            while l<r:
                if nums[l]+nums[r]>nums[i]:     #固定最大的,只用判断一组两边之和大于第三 nums边;较小的元素逐一靠近
                    # print(l,r)
                    ans+=max((r-l),0)
                    r-=1
                else:
                    l+=1
        return ans

nums = [2,2,3,4]
s=Solution()
r=s.triangleNumber(nums)
print(r)

55. 跳跃游戏
# 55. 跳跃游戏
# 给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
# 数组中的每个元素代表你在该位置可以跳跃的最大长度。
# 判断你是否能够到达最后一个下标。
# 输入:nums = [2,3,1,1,4]
# 输出:true
# 解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
# nums = [3,2,1,0,4]
# 输出:false

# 我们依次遍历数组中的每一个位置,并实时维护 最远可以到达的位置。对于当前遍历到的位置
# x,如果它在 最远可以到达的位置 的范围内,那么我们就可以从起点通过若干次跳跃到达该位置,因此我们可以用
# x+nums[x] 更新 最远可以到达的位置。
# 在遍历的过程中,如果 最远可以到达的位置 大于等于数组中的最后一个位置,那就说明最后一个位置可达,我们就可以直接返回 True 作为答案。反之,如果在遍历结束后,最后一个位置仍然不可达,我们就返回 False 作为答案。


class Solution:
    # def canJump(self, nums: List[int]) -> bool:
    def canJump(self, nums):
        max_jump=0
        for i in range(len(nums)):
            if(i<=max_jump):
                max_jump=max(max_jump,nums[i]+i)
                if(max_jump>=len(nums)-1):
                    return True
        return False

# nums = [2,3,1,1,4]
# nums = [3,2,1,0,4]
nums=[1,2,3]
s=Solution()
r=s.canJump(nums)
print(r)

105. 从前序与中序遍历序列构造二叉树
# 105. 从前序与中序遍历序列构造二叉树
# 给定两个整数数组preorder 和 inorder,其中preorder 是二叉树的先序遍历, inorder是同一棵树的中序遍历,请构造二叉树并返回其根节点。
#
# 输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
# 输出: [3,9,20,null,null,15,7]



# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    # def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
    def buildTree(self, preorder, inorder):
        if not preorder and not inorder:
            return None
        val=preorder[0]
        val_i=inorder.index(val)

        root=TreeNode(val)
        root.left=self.buildTree(preorder[1:val_i+1],inorder[0:val_i])
        root.right=self.buildTree(preorder[val_i+1:],inorder[val_i+1:])
        return root
169. 多数元素
# 169. 多数元素
# 给定一个大小为 n 的数组nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于⌊ n/2 ⌋的元素。
# 你可以假设数组是非空的,并且给定的数组总是存在多数元素。
# 输入:nums = [3,2,3]
# 输出:3

class Solution:
    # def majorityElement(self, nums: List[int]) -> int:
    def majorityElement(self, nums):
        num=nums[0]
        cnt=1
        k=1
        while k<len(nums):
            if(nums[k]==num):
                cnt+=1
            else:
                cnt-=1
            if(cnt<0):
                num=nums[k]
                cnt=1
            k+=1
        return num
nums = [3,2,3,2,2,1,1,2,2]
s=Solution()
r=s.majorityElement(nums)
print(r)
209. 长度最小的子数组
# 209. 长度最小的子数组
# 给定一个含有n个正整数的数组和一个正整数 target 。
#
# 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
# 输入:target = 7, nums = [2,3,1,2,4,3]
# 输出:2
# 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

class Solution:
    # def minSubArrayLen(self, target: int, nums: List[int]) -> int:
    def minSubArrayLen(self, target, nums) :
        l,r=0,0
        total=0
        ans=len(nums)
        flag=True
        while r<len(nums):
            total+=nums[r]
            r+=1
            while total>=target:
                flag=False
                ans=min(ans,r-l)
                total -= nums[l]
                l+=1
        if(flag):
            return 0
        return ans
162. 寻找峰值
# 162. 寻找峰值
# 峰值元素是指其值严格大于左右相邻值的元素。
# 给你一个整数数组nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
# 你可以假设nums[-1] = nums[n] = -∞ 。
# 你必须实现时间复杂度为 O(log n) 的算法来解决此问题。
# 输入:nums = [1,2,3,1]
# 输出:2
# 解释:3 是峰值元素,你的函数应该返回其索引 2。
# 输入:nums = [1,2,1,3,5,6,4]
# 输出:1 或 5
# 解释:你的函数可以返回索引 1,其峰值元素为 2;或者返回索引 5, 其峰值元素为 6。


class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        l,r=0,len(nums)-1
        while(l<r):
            m=(l+r)//2
            if(m>0 and nums[m]<=nums[m-1]) or (m<len(nums)-1 and nums[m]>nums[m+1]):
                r=m
            else:
                l=m+1
        return l
74. 搜索二维矩阵
与240算法解法一样
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:

每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        r,c=0,len(matrix[0])-1
        while r<len(matrix) and c>=0:
            if(matrix[r][c]==target):
                return True
            elif(matrix[r][c]>target):
                c-=1
            else:
                r+=1
        return False

40. 组合总和 II
# 40. 组合总和 II
# 给定一个候选人编号的集合candidates和一个目标数target,找出candidates中所有可以使数字和为target的组合。
# candidates中的每个数字在每个组合中只能使用一次。
# 注意:解集不能包含重复的组合。
# 输入: candidates = [10,1,2,7,6,1,5], target = 8,
# 输出:
# [
# [1,1,6],
# [1,2,5],
# [1,7],
# [2,6]
# ]


class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        ans=[]
        t=[]
        def dfs(s,target):
            if target==0:
                ans.append(t[::])
                return
            if target<0:
                return 
            for i in range(s,len(candidates)):
                if(i>s and candidates[i-1]==candidates[i]):
                    continue
                t.append(candidates[i])
                dfs(i+1,target-candidates[i])
                t.pop() 
        dfs(0,target)
        return ans 
1031. 两个非重叠子数组的最大和
# 1031. 两个非重叠子数组的最大和
# 给出非负整数数组 A ,返回两个非重叠(连续)子数组中元素的最大和,子数组的长度分别为 L 和 M。(这里需要澄清的是,长为L的子数组可以出现在长为M的子数组之前或之后。)
#
# 从形式上看,返回最大的 V,而 V = (A[i] + A[i+1] + ... + A[i+L-1]) + (A[j] + A[j+1] + ... + A[j+M-1]) 并满足下列条件之一:
#
# 0 <= i < i + L - 1 < j < j + M - 1 < A.length, 或
# 0 <= j < j + M - 1 < i < i + L - 1 < A.length
# 输入:A = [0,6,5,2,2,5,1,9,4], L = 1, M = 2
# 输出:20
# 解释:子数组的一种选择中,[9] 长度为 1,[6,5] 长度为 2。

# 思路:
# 考虑题意: 必然存在一条分界线把 A 拆分成两半,存在两大类情况:
# 长度为 L 的连续子数组在左边, 长度为 M 的连续子数组在右边
# 或者反过来长度为 M 的连续子数组在左边, 长度为 L 的连续子数组在右边
# 引入
#
# dp[i][0]: 从 A[0]-A[i] 连续 L 长度子数组最大的元素和
# dp[i][1]: 从 A[0]-A[i] 连续 M 长度子数组最大的元素和
# dp[i][2]: 从 A[i]-A[A.size()-1] 连续 L 长度子数组最大的元素和
# dp[i][3]: 从 A[i]-A[A.size()-1] 连续 M 长度子数组最大的元素和
# 某些超出范围的下标, 值设置为 0 (默认值)
# 代码中首先用滑动窗口计算了 dp, 然后将 dp 分成两组, 计算两大类情况下的结果,取最大值返回即可
#



class Solution:
    # def maxSumTwoNoOverlap(self, nums: List[int], firstLen: int, secondLen: int) -> int:
    def maxSumTwoNoOverlap(self, nums, firstLen, secondLen):
        # 滑动窗口的值枚举
        nums_win1=[]   #firstLen为窗口的枚举
        nums_win2=[]   #secondLen为窗口的枚举
        for i in range(len(nums)-firstLen+1):
            nums_win1.append(sum(nums[i:i+firstLen]))

        for i in range(len(nums)-secondLen+1):
            nums_win2.append(sum(nums[i:i+secondLen]))

        # print(nums,'\n',firstLen,secondLen,'\n',nums_win1,'\n',nums_win2)

        ans=0
        len1=len(nums)-firstLen+1
        len2=len(nums)-secondLen+1
        # print(len1,len2,min(len2-firstLen,len1),min(len1-secondLen,len2))
        for i in range(1,len1):     #i<len1;i+firstLen-1<len2
            if(i+firstLen<len2+1):
                ans=max(ans,max(nums_win1[0:i])+max(nums_win2[i-1+firstLen:]))

        for i in range(1,len2):   #i<len1;i+secondLen-1<len1
            if(i+secondLen<len1+1):
                ans=max(ans,max(nums_win2[0:i])+max(nums_win1[i+secondLen-1:]))
        return ans

A = [0,6,5,2,2,5,1,9,4]
L = 1
M = 2

# A=[3,8,1,3,2,1,8,9,0] #29  [3,8,1] [8,9]
# L=3
# M=2
# A=[2,1,5,6,0,9,5,0,3,8] #31 [5,6,0,9] [0,3,8]
# M=4
# L=3
# A=[1,0,3]
# M=1
# L=2
s=Solution()
r=s.maxSumTwoNoOverlap(A,L,M)
print(r)
73. 矩阵置零
# 73. 矩阵置零
# 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
# 输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
# 输出:[[1,0,1],[0,0,0],[1,0,1]]
# 输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
# 输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]

class Solution:
    # def setZeroes(self, matrix: List[List[int]]) -> None:
    def setZeroes(self, matrix) :
        """
        Do not return anything, modify matrix in-place instead.
        """
        m,n=len(matrix),len(matrix[0])
        col_zero=False
        row_zero=False
        for i in range(m):
            if matrix[i][0]==0:
                col_zero=True

        for j in range(n):
            if matrix[0][j]==0:
                row_zero=True


        for i in range(1,m):
            for j in range(1,n):
                if(matrix[i][j]==0):
                    matrix[i][0]=0
                    matrix[0][j]=0

        for i in range(1,m):
            if matrix[i][0]==0:
                for j in range(n):
                    matrix[i][j]=0

        for j in range(1,n):
            if(matrix[0][j]==0):
                for i in range(m):
                    matrix[i][j]=0

        if col_zero:
            for i in  range(m):
                matrix[i][0]=0
        if row_zero:
            for j in range(n):
                matrix[0][j]=0

# matrix = [[1,1,1],[1,0,1],[1,1,1]]
matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
print(matrix)
s=Solution()
s.setZeroes(matrix)
print(matrix)

剑指 Offer 29. 顺时针打印矩阵
#输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
# 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
# 输出:[1,2,3,6,9,8,7,4,5]
# 与54题的差异是这个matrix可以为空
class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix:
            return []
        m,n=len(matrix),len(matrix[0])
        t,b,l,r=0,m-1,0,n-1
        ans=[]
        while(t<=b and l<=r):
            for i in range(l,r+1): #上
                ans.append(matrix[t][i])
            t+=1
            for i in range(t,b+1):  #右
                ans.append(matrix[i][r])
            r-=1
            if(l<=r and t<=b):            #上、右均变化,防止重复计算
                for i in range(r,l-1,-1): #下
                    ans.append(matrix[b][i])
                b-=1
                for i in range(b,t-1,-1): #左
                    ans.append(matrix[i][l])
                l+=1
        return ans
78. 子集
# 78. 子集
# 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
# 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
# 输入:nums = [1,2,3]
# 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

from typing import List
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res=[]
        t=[]

        def dfs(h):
            res.append(t[::])
            for i in range(h,len(nums)):
                if(i>0 and nums[i-1]==nums[i]):
                    continue
                t.append(nums[i])
                dfs(i+1)
                t.pop()
        dfs(0)
        return res

nums = [1,2,3]
s=Solution()
r=s.subsets(nums)
print(r)

面试题 10.03. 搜索旋转数组
# 面试题 10.03. 搜索旋转数组
# 搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。
# 输入: arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 5
# 输出: 8(元素5在该数组中的索引)
#  输入:arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 11
#  输出:-1 (没有找到)

# https://leetcode.cn/problems/search-rotate-array-lcci/solution/er-fen-fa-by-armeria-program/  图解很详细

from typing import List
class Solution:
    def search(self, arr: List[int], target: int) -> int:
        l,r=0,len(arr)-1
        while(l<r):
            m=(l+r)//2
            print("#1:",l,r,m,arr[m])
            if(arr[l]<arr[m]):
                if(arr[l]<=target and target<=arr[m]):   #左边界单调增且target在此区间
                    print('@1')
                    r=m
                else:
                    print('@2')
                    l=m+1
            elif(arr[l]>arr[m]):
                if(arr[l]<=target or target<=arr[m]): #左边界不单调且target在此区间
                    print('@3')
                    r=m
                else:
                    print('@4')
                    l=m+1
            elif(arr[l]==arr[m]):
                if(arr[l]==target):
                    print('@5')
                    r=l
                else:
                    print('@6')
                    l+=1      #去掉重复的数
            print("#2:",l,r)
        return l if arr[l]==target else -1


# class Solution:
#     def search(self, nums: List[int], target: int) -> int:
#         if not nums:
#             return -1
#         left, right = 0, len(nums) - 1
#         while left < right:                                         # 循环结束条件left==right
#             mid = (left + right) >> 1
#             if nums[left] < nums[mid]:                              # 如果左值小于中值,说明左边区间升序
#                 if nums[left] <= target and target <= nums[mid]:    # 如果目标在左边的升序区间中,右边界移动到mid
#                     print('@1')
#                     right = mid
#                 else:                                               # 否则目标在右半边,左边界移动到mid+1
#                     print('@2')
#                     left = mid + 1
#             elif nums[left] > nums[mid]:                            # 如果左值大于中值,说明左边不是升序,右半边升序
#                 if nums[left] <= target or target <= nums[mid]:     # 如果目标在左边,右边界移动到mid
#                     print('@3')
#                     right = mid
#                 else:                                               # 否则目标在右半边的升序区间中,左边界移动到mid+1
#                     print('@4')
#                     left = mid + 1
#             elif nums[left] == nums[mid]:                           # 如果左值等于中值,可能是已经找到了目标,也可能是遇到了重复值
#                 if nums[left] != target:                            # 如果左值不等于目标,说明还没找到,需要逐一清理重复值
#                     print('@5')
#                     left += 1
#                 else:                                               # 如果左值等于目标,说明已经找到最左边的目标值
#                     print('@6')
#                     right = left                                    # 将右边界移动到left,循环结束
#         return left if nums[left] == target else -1                 # 返回left,或者-1






# a=[15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14]
# target=5
# a=[1,1,1,1,1,2,1,1,1]
# target=2
a=[5,5,5,1,2,3,4,5]
target=5
s=Solution()
r=s.search(a,target)
print(r)
153. 寻找旋转排序数组中的最小值
# 153. 寻找旋转排序数组中的最小值
# 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
# 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
# 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
# 注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。
# 给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
# 你必须设计一个时间复杂度为O(log n) 的算法解决此问题。
# 输入:nums = [3,4,5,1,2]
# 输出:1
# 解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

from typing import List
class Solution:
    def findMin(self, nums: List[int]) -> int:
        l,r=0,len(nums)-1
        while(l<r):
            m=(l+r)//2
            if(nums[m]<=nums[-1]):
                r=m
            else:
                l=m+1
        return nums[l]
509. 斐波那契数
# 509. 斐波那契数
# 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:\
# F(0) = 0,F(1) = 1
# F(n) = F(n - 1) + F(n - 2),其中 n > 1
# 给定 n ,请计算 F(n) 。


class Solution:
    # def fib(self, n: int) -> int:
    def fib(self, n) :
        a,b=0,1
        for i in range(n):
            t=b
            b=a+b
            a=t
        return a

s=Solution()
r=s.fib(2)
print(r)
287. 寻找重复数
# 287. 寻找重复数
# 给定一个包含n + 1 个整数的数组nums ,其数字都在[1, n]范围内(包括 1 和 n),可知至少存在一个重复的整数。
# 假设 nums 只有 一个重复的整数 ,返回这个重复的数 。
# 你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。
# 输入:nums = [1,3,4,2,2]
# 输出:2
class Solution:
    # def findDuplicate(self, nums: List[int]) -> int:
    def findDuplicate(self, nums) :
        print("#",nums)
        for i in range(len(nums)):
            k=1
            while nums[nums[i]-1]!=nums[i]:  #交换多次次,将i-1的位置放值为i的nums[i]
                t=nums[nums[i]-1]
                nums[nums[i]-1]=nums[i]
                nums[i]=t
                k+=1

            if (nums[nums[i] - 1] == nums[i] and nums[i] - 1 != i):
                return nums[i]
        return -1
s=Solution()
nums = [1,3,4,2,2]
r=s.findDuplicate(nums)
print(r)
#快慢指针的方法
class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int slow = 0, fast = 0;
        do {
            slow = nums[slow];
            fast = nums[nums[fast]];
        } while (slow != fast);
        slow = 0;
        while (slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
};
718. 最长重复子数组
# 动态规划解法;a[i][j]表示nums1与nums2的公共最大公共字串的量
# class Solution:
#     # def findLength(self, nums1: List[int], nums2: List[int]) -> int:
#     def findLength(self, nums1, nums2):
#         m,n=len(nums1),len(nums2)
#         a=[[0]*(n+1) for i in range(m+1)]
#
#         for i in range(m):
#             for j in range(n):
#                 if(nums1[i]==nums2[j]):
#                     a[i+1][j+1]=a[i][j]+1
#                 else:
#                     a[i + 1][j + 1] = 0
#         res=0
#         for i in range(1,m+1):
#             for j in range(1,n+1):
#                 res=max(res,a[i][j])
#         return res


# 滑动窗口
#  我们可以枚举 A 和 B 所有的对齐方式。对齐的方式有两类:第一类为 A 不变,B 的首元素与 A 中的某个元素对齐;第二类为 B 不变,
#  A 的首元素与 B 中的某个元素对齐。对于每一种对齐方式,我们计算它们相对位置相同的重复子数组即可。
class Solution:
    # def findLength(self, nums1: List[int], nums2: List[int]) -> int:
    def findLength(self, nums1, nums2):
        m,n=len(nums1),len(nums2)
        res=0

        def maxLen(i,j,len):   #i为a的开始;j为b的开始;len为保证两者不溢出的长度
            max_len=0
            cur_len=0
            for k in range(len):
                if(nums1[i+k]==nums2[j+k]):
                    cur_len+=1
                else:
                    cur_len=0
                max_len = max(max_len, cur_len)
            # print(max_len)
            return max_len

        # nums1动对齐
        for i in range(m):
            l=min(n,m-i)
            res = max(res, maxLen(i,0,l))

        # nums2动对齐
        for i in range(n):
            l=min(m,n-i)
            res=max(res,maxLen(0,i,l))
        return res
189. 轮转数组
class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n=len(nums)
        k=k%n 
        # ans=nums[n-k:]+nums[0:n-k]
        # print(ans)  这种方式正确,但是函数无返回
        nums[n-k:]=nums[n-k:][::-1]
        nums[0:n-k]=nums[0:n-k][::-1]
        nums[:]=nums[::-1]
167. 两数之和 II - 输入有序数组
# 167. 两数之和 II - 输入有序数组
# 给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。
#
# 以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。
#
# 你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
#
# 你所设计的解决方案必须只使用常量级的额外空间。

# 输入:numbers = [2,7,11,15], target = 9
# 输出:[1,2]
# 解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        l,r=0,len(numbers)-1
        while(l<r):
            t=numbers[l]+numbers[r]
            if(t==target):
                return [l+1,r+1]
            elif(t>target):
                r-=1
            else:
                l+=1
        return [-1,-1]
238. 除自身以外数组的乘积
class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        ans=[1]*len(nums)
        forward=[1]*len(nums)
        for i in range(len(nums)-1):
            forward[i+1]=forward[i]*nums[i]
        # print(forward)
        back=1
        for i in range(len(nums)-1,-1,-1):
            ans[i]=back*forward[i]
            back*=nums[i]
        return ans

79. 单词搜索
# 79. 单词搜索
#
# 给定一个m x n 二维字符网格board 和一个字符串单词word 。如果word 存在于网格中,返回 true ;否则,返回 false 。
#
# 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
#
# 输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
# 输出:true

class Solution:
    # def exist(self, board: List[List[str]], word: str) -> bool:
    def exist(self, board, word) :

        def dfs(h,i,j):
            if(h==len(word)):
                return True
            valid=False
            if i>=0 and i<len(board) and j >=0 and j <len(board[0]) and not flag[i][j] and word[h]==board[i][j]:
                flag[i][j] = True
                valid=dfs(h+1,i+1,j) or dfs(h+1,i-1,j) or dfs(h+1,i,j-1) or dfs(h+1,i,j+1)
                flag[i][j]=False
            return valid

        find=False
        for i in range(len(board)):
            for j in range(len(board[0])):
                flag = [[False] * len(board[0]) for i in range(len(board))]
                find=dfs(0,i,j)
                if(find):
                    return True
        return find

# board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]]
# word = "ABCCED"
# board = [["a","b"],["c","d"]]
# word = "acdb"
board =[["A","B","C","E"],["S","F","E","S"],["A","D","E","E"]]
word ="ABCESEEEFS"
s=Solution()
r=s.exist(board,word)
print(r)
剑指 Offer 04. 二维数组中的查找
# 剑指 Offer 04. 二维数组中的查找
# 在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
# [
#   [1,   4,  7, 11, 15],
#   [2,   5,  8, 12, 19],
#   [3,   6,  9, 16, 22],
#   [10, 13, 14, 17, 24],
#   [18, 21, 23, 26, 30]
# ]
# 给定 target = 5,返回 true。
# 给定 target = 20,返回 false。

class Solution:
    # def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool
    def findNumberIn2DArray(self, matrix, target) :
        if not matrix:
            return False
        i,j=0,len(matrix[0])-1
        while i<len(matrix) and j>=0:
            if target==matrix[i][j]:
                return True
            elif target>matrix[i][j]:
                i+=1
            else:
                j-=1
        return False

s=Solution()
matrix=[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
target=9
r=s.findNumberIn2DArray(matrix,target)
print(r)
670. 最大交换
# 670. 最大交换
# 给定一个非负整数,你至多可以交换一次数字中的任意两位。返回你能得到的最大值。
# 输入: 2736
# 输出: 7236
# 解释: 交换数字2和数字7
class Solution:
    # def maximumSwap(self, num: int) -> int:
    def maximumSwap(self, num):
        s=str(num)
        l,r=0,len(s)-1
        h=[-1]*10
        for i,c in  enumerate(s):
            num=int(c)-1
            h[num]=i
        print(h)

        for j,c in enumerate(s):
            t = int(c) - 1
            for i in range(8, -1, -1):
                if h[i] == -1:
                    continue
                if(i>t and h[i]>j):
                    lis=list(s)
                    lis[h[i]],lis[j]=lis[j],lis[h[i]]
                    s=''.join(lis)
                    return int(s)
        return int(s)
s=Solution()
# num=2736
num=9973
r=s.maximumSwap(num)
print(r)
75. 颜色分类
# 75. 颜色分类
# 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
#
# 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
#
# 必须在不使用库的sort函数的情况下解决这个问题
# 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
#
# 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
#
# 必须在不使用库的sort函数的情况下解决这个问题

# 输入:nums = [2,0,2,1,1,0]
# 输出:[0,0,1,1,2,2]


from typing import List

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        h=[0]*3
        for num in nums:
            h[num]+=1

        k=0
        for i in range(3):
            for j in range(h[i]):
                nums[k]=i
                k+=1
nums = [2,0,2,1,1,0]
s=Solution()
s.sortColors(nums)
print(nums)
581. 最短无序连续子数组

给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

请你找出符合题意的 最短 子数组,并输出它的长度。

输入:nums = [2,6,4,8,10,9,15]
输出:5
解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        left=[nums[0]]*len(nums)
        right=[nums[-1]]*len(nums)
        for i in range(1,len(nums)):
            left[i]=max(left[i-1],nums[i])

        for i in range(len(nums)-2,-1,-1):
            right[i]=min(right[i+1],nums[i])


        l,r=-1,-1
        for i in range(len(nums)):
            if left[i]>nums[i] or nums[i]>right[i]:
                l=i
                break 

        for i in range(len(nums)-1,-1,-1):
            if left[i]>nums[i] or nums[i]>right[i]:
                r=i
                break
        if l==r and l==-1:
            return 0
        return r-l+1
剑指 Offer 53 - I. 在排序数组中查找数字 I
# 剑指 Offer 53 - I. 在排序数组中查找数字 I
# 统计一个数字在排序数组中出现的次数。
# 输入: nums = [5,7,7,8,8,10], target = 8
# 输出: 2

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if len(nums) == 0:
            return 0
        l, r = 0, len(nums) - 1
        while (l < r):
            m = (l + r) // 2
            if (nums[m] >= target):
                r = m
            else:
                l = m + 1

        if (nums[l] != target):
            return 0
        ans, l1 = 0, l
        l, r = l, len(nums) - 1
        while (l < r):
            m = (l + r + 1) // 2
            if (nums[m] <= target):
                l = m
            else:
                r = m - 1
        if (nums[l] == target):
            ans = l - l1 + 1
        return ans
442. 数组中重复的数据
class Solution:
    def findDuplicates(self, nums: List[int]) -> List[int]:
        ans=[]
        for i in range(len(nums)):
            while(nums[i]!=nums[nums[i]-1]):
                nums[nums[i]-1],nums[i]=nums[i],nums[nums[i]-1]
        for i ,v in enumerate(nums):
            if i!=v-1:
                ans.append(v)
        return ans
380. O(1) 时间插入、删除和获取随机元素
# 实现RandomizedSet 类:
# RandomizedSet() 初始化 RandomizedSet 对象
# bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false 。
# bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false 。
# int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。
# 你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O(1) 。


class RandomizedSet:
    def __init__(self):
        self.val_index={}
        self.vals=[]

    def insert(self, val: int) -> bool:
        if(val in self.val_index):
            return False
        else:
            self.vals.append(val)
            self.val_index[val]=len(self.vals)
            return True

    def remove(self, val: int) -> bool:
        if val in self.val_index:
            index=self.val_index[val]
            self.val_index[self.vals[-1]]=index
            self.vals[index-1]=self.vals[-1]
            self.vals.pop()
            self.val_index.pop(val)
            return True
        else:
            return False


    def getRandom(self) -> int:
        import random
        num=random.choice(self.vals)
        return num




# Your RandomizedSet object will be instantiated and called as such:
# obj = RandomizedSet()
# param_1 = obj.insert(val)
# param_2 = obj.remove(val)
# param_3 = obj.getRandom()
26. 删除排序数组中的重复项
# 26. 删除有序数组中的重复项
# 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
#
# 由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
#
# 将最终结果插入 nums 的前 k 个位置后返回 k 。
#
# 不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        l,r,n=0,0,len(nums)
        while(r<n):
            while(nums[l]==nums[r]):
                r+=1
            nums[l+1]=nums[r]
            l+=1
        return l+1
面试题 16.16. 部分排序
# 面试题 16.16. 部分排序
# 给定一个整数数组,编写一个函数,找出索引m和n,只要将索引区间[m,n]的元素排好序,整个数组就是有序的。注意:n-m尽量最小,也就是说,找出符合条件的最短序列。函数返回值为[m,n],若不存在这样的m和n(例如整个数组是有序的),请返回[-1,-1]。
# 输入: [1,2,4,7,10,11,7,12,6,7,16,18,19]
# 输出: [3,9]

from typing import List
class Solution:
    def subSort(self, array: List[int]) -> List[int]:
        if len(array)<2:
            return [-1,-1]
        l,r=1,len(array)-1

        while(l<len(array) and array[l-1]<=array[l]):
            l+=1
        if(l==len(array)):
            return [-1,-1]
        while(array[r]>array[l-1] and array[r]>=array[r-1] ):
            r-=1
        # print(l-1,r+1)
        l,r=l-1,r+1    #满足条件的节点为[0,l-1],[r+1,len(array)-1]
        min_i,max_i = l+1,r-1
        for i in range(l , r):
            if (array[min_i] >= array[i]):
                min_i = i
            if (array[max_i] <= array[i]):
                max_i = i
        # print('&',array[min_i],array[max_i],'#',min_i,max_i,l,r)
        while(r<len(array) and  array[max_i]>array[r]):
            r+=1
        while(l>=0 and array[min_i]<array[l]):
            l-=1
        return [l+1,r-1]



a=[1,2,4,7,10,11,7,12,6,7,16,18,19]
# a=[1,3,5,7,9]
print(len(a))
s=Solution()
r=s.subSort(a)
print(r)

16. 最接近的三数之和
# 16. 最接近的三数之和
# 给你一个长度为n的整数数组nums和一个目标值target。请你从nums中选出三个整数,使它们的和与target最接近。返回这三个数的和。

from typing import List
class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        nums.sort()
        closest=sum(nums[0:3])
        for i in range(len(nums)):
            if(i>0 and nums[i-1]==nums[i]):
                continue
            l,r=i+1,len(nums)-1
            while(l<r):
                total=nums[i]+nums[l]+nums[r]
                if abs(closest-target)>abs(total-target):
                    closest=total

                if(total==target):
                    return closest
                elif(total>target):
                    r-=1
                    while (l<r and nums[r]==nums[r+1]):
                        r-=1
                else:
                    l+=1
                    while (l < r and nums[l] == nums[l-1]):
                        l+=1
        return closest
1208. 尽可能使字符串相等
# 1208. 尽可能使字符串相等
# 给你两个长度相同的字符串,s 和 t。
# 将 s中的第i个字符变到t中的第 i 个字符需要|s[i] - t[i]|的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。
# 用于变更字符串的最大预算是maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。
# 如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。
# 如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0。
#
# 输入:s = "abcd", t = "bcdf", maxCost = 3
# 输出:3
# 解释:s 中的 "abc" 可以变为 "bcd"。开销为 3,所以最大长度为 3。

class Solution:
    def equalSubstring(self, s: str, t: str, maxCost: int) -> int:
        a=[]
        for i in range(len(s)):
            a.append(abs(ord(s[i])-ord(t[i])))

        l,r=0,0
        tol=0
        ans=0
        while(r<len(a)):
            tol+=a[r]
            r+=1
            if(tol>maxCost):
                tol-=a[l]
                l+=1
            ans=max(ans,r-l)
        return ans
1122. 数组的相对排序
# 1122. 数组的相对排序
# 给你两个数组,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]

from typing import List
class Solution:
    def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
        h,t={},[]
        for num in arr2:
            h[num]=0
        for i in range(len(arr1)-1,-1,-1):
            if arr1[i] in h:
                h[arr1[i]]+=1
            else:
                t.append(arr1[i])

        p=0
        for num in arr2:
            for q in range(h[num]):
                arr1[p]=num
                p+=1
        t.sort()
        for num in t:
            arr1[p]=num
            p+=1
        return arr1

arr1 = [2,3,1,3,2,4,6,7,9,2,19]
arr2 = [2,1,4,3,9,6]
s=Solution()
r=s.relativeSortArray(arr1,arr2)
print(r)
57. 插入区间
# 57. 插入区间
# 给你一个 无重叠的 ,按照区间起始端点排序的区间列表。
# 在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)
# 输入:intervals = [[1,3],[6,9]], newInterval = [2,5]
# 输出:[[1,5],[6,9]]

from typing import List
class Solution:
    def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
        intervals.append(newInterval)
        if len(intervals)<=1:
            return intervals
        intervals.sort(key=lambda x:x[0])
        res=[intervals[0]]
        for i in range(len(intervals)):
            if res[-1][1]>=intervals[i][0]:
                res[-1][1]=max(res[-1][1],intervals[i][1])
            else:
                res.append(intervals[i])
        return res
18. 四数之和
class Solution:
    # def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
    def fourSum(self, nums, target) :
        nums.sort()
        ans=[]
        n=len(nums)
        for i in range(n-3):
            if i>0 and nums[i-1]==nums[i]:
                continue
            if nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target:
                break
            if nums[i]+nums[n-1]+nums[n-2]+nums[n-3]<target:
                continue
            for j in range(i+1,n-2):
                if j > i+1 and nums[j - 1] == nums[j]:
                    continue
                if nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target:
                    break
                if nums[i] + nums[j] + nums[n - 1] + nums[n - 2] < target:
                    continue
                l,r=j+1,n-1
                while(l<r):
                    # print(nums)
                    total=nums[i]+nums[j]+nums[l]+nums[r]
                    # print(i,j,l,r,total)
                    if(total==target):
                        ans.append([nums[i], nums[j], nums[l], nums[r]])
                        while(l<r and nums[l]==nums[l+1]):
                            l+=1
                        l+=1
                        while(l<r and nums[r]==nums[r-1]):
                            r-=1
                        r-=1
                    elif(total>target):
                        r-=1
                    else:
                        l+=1
        return ans
1539. 第 k 个缺失的正整数
# 1539. 第 k 个缺失的正整数
# 给你一个 严格升序排列 的正整数数组 arr 和一个整数 k 。
#
# 请你找到这个数组里第 k 个缺失的正整数。
#
# 输入:arr = [2,3,4,7,11], k = 5
# 输出:9
# 解释:缺失的正整数包括 [1,5,6,8,9,10,12,13,...] 。第 5 个缺失的正整数为 9 。




class Solution:
    # def findKthPositive(self, arr: List[int], k: int) -> int:
    def findKthPositive(self, arr, k) :
        cnt = 0
        ans = -1
        num=1
        i=0
        while(cnt<k):
            if(i<len(arr) and arr[i]==num):
                i+=1
            else:
                cnt+=1
                if(cnt==k):
                    break
            num+=1
        ans=num
        return ans

s=Solution()
nums=[2,3,4,7,11]
k=5
# nums=[1,2]
# k=1
r=s.findKthPositive(nums,k)
print(r)
268. 缺失数字
# 268. 丢失的数字
# 给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。
# 输入:nums = [3,0,1]
# 输出:2
# 解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。


from typing import List
class Solution:
    def missingNumber(self, nums: List[int]) -> int:
        h={}
        for i in nums:
            h[i]=1
        for i in range(len(nums)+1):
            if i not in h:
                return i
        return -1

# 位运算方法,异或
from typing import List
class Solution:
    def missingNumber(self, nums: List[int]) -> int:
       num=0
       for i in nums:
           num^=i
       for i in range(len(nums)+1):
           num^=i
       return num

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值