【刷题笔记(一起刷题)】Leetcode 面试最常考100题(负雪明烛整理题集)

Leetcode刷题笔记(记录答案+我遇到的问题)

坚持刷题,持续更新……欢迎监督

目录

数组

88.合并两个有序数组

240.搜索二维矩阵Ⅱ

74.搜索二维矩阵

哈希表

1.两数之和

二分法

704.二分查找(简单)

35.  搜索插入位置(简单)

69.  x的平方根(简单)

367.有效的完全平方数(简单)

441.排列硬币(简单)

33.  搜索旋转排序数组(中等)

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

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

162.寻找峰值(中等)

4.    寻找两个正序(困难)

排序

912.排序数组

双指针

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

动态规划

53.最大子数组和


数组

88.合并两个有序数组

题目要求:

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

来源:力扣(LeetCode)
链接:力扣

题解&问题

方法一:合并两个数组给nums,进行排序,排完再还给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.
        """
        nums=nums1[:m]
        for i in range(n):
            nums.append(nums2[i])
            i+=1
        nums.sort()
        for i, num in enumerate(nums):
            nums1[i] = num

用下面的方法print(nums1)出来的结果满足测试用例,但是平台给出的输出就和nums1给的初值一样,不清楚为什么。

知道原因啦:因为nums1的长度本身就是m+n,合并12后长度为m+2n。中间的0并没有去掉。利用新数组nums就是为了把0去掉。

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.
        """
        nums1=nums1[:m]
        for i in range(n):
            nums1.append(nums2[i])
            i+=1
        nums1.sort()

方法二:(参考负雪明烛)两个数组从尾部开始比较大小,更大的放在nums1的最后一位。如果nums2还有剩余,则放在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.
        """
        while m>0 and n>0:
            if nums1[m-1]>nums2[n-1]:
                nums1[m+n-1]=nums1[m-1]
                m-=1
            else:  #nums1[m-1]<=nums2[n-1]
                nums1[m+n-1]=nums2[n-1]
                n-=1
        nums1[:n]=nums2[:n]     # 如果nums2全部都已经添加到nums1里面,此时n=0,该句对结果没有影响。
                                # 如果nums2还有剩余,则全部放在nums1前方n个位置处

参考链接:【LeetCode】88. Merge Sorted Array 解题报告(Java & Python)_负雪明烛的博客-CSDN博客

240.搜索二维矩阵Ⅱ

题目要求:

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

每行的元素从左到右升序排列。
每列的元素从上到下升序排列。

来源:力扣(LeetCode)
链接:力扣

题解&问题:

方法一:(解题思路参考负雪明烛)因为矩阵是有顺序的,所以:

指针从矩阵左下角开始,

如果当前值<target,说明target在本行右侧;

如果当前值>target,说明target在上一行里;

如果当前值==target,return True。

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        m=len(matrix)     #行
        n=len(matrix[0])  #列
        p=m-1  #行
        q=0    #列
        if not matrix or not matrix[0]:
            return False
        while True:
            if p>-1 and q<n:
                if matrix[p][q]>target:
                    p-=1
                elif matrix[p][q]==target:
                    return True
                else:
                    q+=1
            else:
                return False

问题:(下方代码没有通过)

我第一遍自己写的时候用的while,导致的结果:target不在matrix中的时候,会反反复复的查找。

是因为while只要没达到条件就会一直循环,而if则可以在递增到指定条件限制的时候停止?!

import numpy as np
class Solution:
    def searchMatrix(self, matrix, target: int) -> bool:
        matrix=np.array(matrix)
        m=matrix.shape[0] #行
        n=matrix.shape[1] #列
        p=m-1   #行
        q=0     #列
        while p!=-1 or q!=n:
            temp=matrix[p][q]
            if temp<target:
                q+=1
            elif temp>target:
                p-=1
            else:
                return True
        return False

笔记:

if not 用法:

not matrix      #矩阵为空??
not matrix[0]   #矩阵列为空??

获得矩阵行列数目的方法:

# method 1
import numpy as np
matrix = np.array(matrix)
row = matrix.shape[0]     # 行
col = matrix.shape[1]     # 列

# method 2
row = len(matrix)         # 行
col = len(matrix[0])      # 列: 第一行的长度

方法二:因为有顺序,所以可以用二分法

对每行都进行二分法比较

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        m=len(matrix)              # 行
        n=len(matrix[0])           # 列
        if m==0 or n==0:
            return False
        elif target>matrix[m-1][n-1]:
            return False
        else:                   
            for i in range(m):               # 每行都用二分法比较
                left,right=0,n-1             # 设置左右边界
                while left<=right:           # 注意此处要加边界限制条件      
                    mid=(left+right)//2      # 设置middle
                    if matrix[i][mid]<target:
                        left=mid+1
                    elif matrix[i][mid]>target:
                        right=mid-1
                    else:
                        return True
            return False

负雪明烛题解链接

【LeetCode】240. Search a 2D Matrix II 解题报告(Python & C++)_负雪明烛的博客-CSDN博客

74.搜索二维矩阵

题目要求:

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:

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

来源:力扣

题解&问题:

因为本题中所有数都是升序排列,所以把二维矩阵看作是一个完全升序的列表,然后二分查找。

class Solution:  
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:         
        h=len(matrix)
        w=len(matrix[0])
        if w==0 or h==0:
            return False 
        left=0
        right=h*w-1          
        while left<=right:
            mid=(left+right)//2
            i=mid//w
            j=mid%w
            if matrix[i][j]<target:
                left=mid+1
            elif matrix[i][j]>target:
                right=mid-1
            else:
                return True
        else:
            return False

哈希表

1.两数之和

题目要求:

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

来源:力扣(LeetCode)
链接:力扣

题解&问题:

方法一

遍历所有数,计算其余每个数是否等于(target-当前值)

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        for i in range(len(nums)):
            for j in range(i+1,len(nums)):
                if nums[j]==target-nums[i]:
                    return i,j

方法二:解题思路参考负雪明烛

用dict实现,先构建字典,然后找(target-当前值)的结果是否在字典中。

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        dic={}
        for i,nums[i] in enumerate(nums):
            dic[nums[i]]=i
        for i,nums[i] in enumerate(nums):
            if target-nums[i] in dic and dic[target-nums[i]]!=i:
                return dic[target-nums[i]],i

方法三(负雪明烛解题思路【HashMap】):

代码先直接粘贴过来,等我研究明白再写思路

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        N = len(nums)
        pos = dict()
        for i, num in enumerate(nums):
            if target - num in pos:
                return [pos[target - num], i]
            else:
                pos[num] = i
        return [0, 0]

负雪明烛原文链接【LeetCode】1. Two Sum 两数之和_负雪明烛的博客-CSDN博客

二分法

704.二分查找(简单)

题目要求

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

来源:力扣(LeetCode)
链接:力扣

题解

思路:典型二分查找

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n=len(nums)
        if n==0:
            return -1
        left,right=0,n-1
        while left<=right:
            mid=(left+right)//2
            if nums[mid]>target:
                right=mid-1
            elif nums[mid]<target:
                left=mid+1
            else:
                return mid
        return -1

35.  搜索插入位置(简单)

题目要求

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

来源:力扣(LeetCode)
链接:力扣

题解

方法一:

思路:因为left和right已经发生的交叉,left>right,所以返回的应该是left。

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        n = len(nums)
        left, right = 0, n-1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] < target:
                left = mid + 1
            elif nums[mid] > target:
                right = mid -1
            else:
                return mid
        return left

Java

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0;
        int right = nums.length -1;
        int mid = 0;
        while (left<=right){
            mid=(left+right)/2;
            if (nums[mid]<target){
                left=mid+1;
            }
            else if(nums[mid]>target){
                right=mid-1;
            }
            else{
                return mid;
            }
        }
        return left;
    }
}

方法二:

思路:Python可以直接用bisect模块。

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        return bisect.bisect_left(nums,target)

69.  x的平方根(简单)

题目要求

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

来源:力扣(LeetCode)

链接:力扣

题解

方法一:暴力解决,从头开始算,直到找到

1.某个数的平方恰好=x,输出该数;2.某个数的平方<x,但(该数+1)的平方>x,输出该数。

但是,该方法时间超限。

class Solution:
    def mySqrt(self, x: int) -> int:
        if x==0 or x==1:
            return x
        else:
            for cur in range(x):
                if cur**2<x and (cur+1)**2>x:
                    return cur
                elif cur**2==x:
                    return cur

方法二:直接用库函数。

import math
class Solution:
    def mySqrt(self, x: int) -> int:
        return int(math.sqrt(x)) 

方法三:牛顿法

牛顿法原理:若想求2的平方根,列公式f(x)=x^2-2。当f(x)=0时,x=根号2。

在f(x)上随便取一点,以(2,2)为例,在该点做f(x)的切线,列出切线方程y=4x-6,求该切线方程在y=0时候的x值,x=1.5,将所求x值带回f(x)=0.25,此时这点坐标为(切线方程和x轴交点,对应的f(x)值)=(1.5,0.25)。

此时对这个点做上述操作:求切线方程y=4x-5.75,切向方程与x轴交点x=1.4375

可以发现切线方程与x轴的交点从x=1.5到x=1.4375,如果继续迭代,x会不断逼近根号二的真值1.4142……,如果最开始的初始值选择别的值,也不会耽误计算,影响的只是迭代次数。

参考链接(里面有图):如何手工开根号?(简述Newton-Raphson 法) - 知乎

数学部分讲完了,接下来是总结规律:

class Solution:
    def mySqrt(self, x: int) -> int:
        t=x
        while t*t>x:
            t=(t+x/t)//2
        return int(t)

方法四:二分法

class Solution:
    def mySqrt(self, x: int) -> int:
        left,right=0,x+1
        while left<=right:
            mid=(left+right)//2
            if mid**2>x:
                right=mid-1
            elif mid**2<x:
                left=mid+1
            else:
                return mid
        return left-1   

牛顿法思路来源负雪明烛,参考链接:【LeetCode】69. Sqrt(x) 解题报告(Python & C++)_负雪明烛的博客-CSDN博客

367.有效的完全平方数(简单)

题目要求

给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。

进阶:不要 使用任何内置的库函数,如  sqrt 。

来源:力扣(LeetCode)
链接:力扣

题解

方法一:二分法

class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        left,right=0,num+1
        while left<=right:
            mid=(left+right)//2
            if mid**2>num:
                right=mid-1
            elif mid**2<num:
                left=mid+1
            else:
                return True
        return False

方法二:利用完全平方数的性质(是从1开始若干连续奇数的和)

class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        i=1
        while num>0:
            num-=i
            i+=2
        return num==0

方法三:牛顿法

class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        t=num
        while t**2>num:
            t=(t+num/t)//2
        return t**2==num

方法二(利用完全平方性质)、方法三(牛顿法)思路来源负雪明烛

参考链接:【LeetCode】367. Valid Perfect Square 解题报告(Java & Python)_负雪明烛的博客-CSDN博客

441.排列硬币(简单)

题目要求

你总共有 n 枚硬币,并计划将它们按阶梯状排列。对于一个由 k 行组成的阶梯,其第 i 行必须正好有 i 枚硬币。阶梯的最后一行 可能 是不完整的。

给你一个数字 n ,计算并返回可形成 完整阶梯行 的总行数。

来源:力扣(LeetCode)
链接:力扣

题解

方法一:暴力尝试,判断是否正好排布,如果正好就返回行数;如果不正好就返回行数-1。

class Solution:
    def arrangeCoins(self, n: int) -> int:
        row=0
        while n>0:
            row+=1
            n-=row
        if n==0:
            return row
        else:
            return row-1

方法二:等差数列前n项和+二分法

#等差数列求和公式
sn=a1*n+n*(n-1)*d/2   # a1:第一项; d:公差
sn=(a1+an)*n/2        # an:第n项
class Solution:
    def arrangeCoins(self, n: int) -> int:
        left,right=0,n+1
        while left<=right:
            mid=(left+right)//2  
            sn=mid+mid*(mid-1)/2  # 等差数列求和公式,第一项a1=1,d=1,所以省略了
                                  # 两个求和公式,用哪个都行
            if sn>n:
                right=mid-1
            elif sn<n:
                left=mid+1
            else:
                return mid
        return left-1

方法三:等差数列前n项和,反向求解行数,并向下取整

sn=(a1+an)*n/2
2*sn=(1+n)*n
n**2+n+1/4=2*sn+1/4        # 中学数学,构成完全平方项
(n+1)**2=2*sn+1/4
n=math.sqrt(2*sn+1/4)-1/2  # 此处的sn是题目要求的目标值n
import math
class Solution:
    def arrangeCoins(self, n: int) -> int:
        return int(math.sqrt(2*n+1/4)-1/2)

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 。

来源:力扣(LeetCode)
链接:力扣

题解

二分法:根据二分法以mid为分界,划分数组左右两侧,使得各自有序,然后在用二分法在target满足的区间内进行寻找。

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left,right=0,len(nums)-1
        while left<=right:
            mid=(left+right)//2
            if nums[mid]==target:
                return mid
            if nums[mid]>nums[right]:     # 左侧有序
                if nums[mid]>target and nums[left]<=target:   # target在有序的左侧,则开始缩小区间搜索
                    right=mid-1
                else:          # target不在有序一侧,则重新划定有序区间
                    left=mid+1
            else:   #nums[mid]<nums[right]: 右侧有序
                if nums[mid]<target and nums[right]>=target:  # target在有序的右侧,则开始缩小区间搜索
                    left=mid+1
                else:          # target不在有序一侧,则重新划定有序区间
                    right=mid-1
        return -1
                

二分法思路来源:负雪明烛。链接:【LeetCode】33. Search in Rotated Sorted Array 解题报告(Python & C++)_负雪明烛的博客-CSDN博客

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

题目要求

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

来源:力扣(LeetCode)
链接:力扣

题解

二分法一:利用二分法找target,找到后确认与target相同的左右边界。

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        left,right=0,len(nums)-1
        while left<=right:
            mid=(left+right)//2
            if nums[mid]>target:  
                right=mid-1
            elif nums[mid]<target:
                left=mid+1
            else:                    # 当利用二分法找到target后,确认左右边界。
                left,right=mid,mid   # 以mid为中心向左右移动
                # 指针左移直到找到与target不同的值(注意左边界不能超过0)
                while left>-1 and nums[left]==nums[mid]: 
                    left-=1
                # 指针右移直到找到与target不同的值(注意右边界不能超过nums的长度)
                while right<len(nums) and nums[right]==nums[mid]: 
                    right+=1
                return left+1,right-1 
        return -1,-1   

二分法二:用python内置函数

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        left=bisect.bisect_left(nums,target)   # left=第一个与target相同的元素下标
        right=bisect.bisect_right(nums,target) # right=最后一个与target相同的元素下标+1
        print("left= ",left,"right= ",right)
        if left==right: #没找到target时,left=right=0
            return -1,-1
        return left,right-1

二分法三:定义两个函数,实现bisect_left,bisect_right。

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        left=self.lowwer_bound(nums,target)
        right=self.higher_bound(nums,target)
        if left==right:
            return -1,-1
        return left,right-1
    
    # target存在时,返回第一个与target相同元素的下标;target不存在时,返回target插入位置。
    def lowwer_bound(self,nums,target): 
        left,right=0,len(nums)-1
        while left<=right:
            mid=(left+right)//2
            if nums[mid]<target:  # 左右边界两个函数只在这个位置有区别
                left=mid+1
            else:
                right=mid-1
        return left
    
    # target存在时,返回右侧第一个与target不同元素下标;target不存在时,返回target插入位置。
    def higher_bound(self,nums,target):
        left,right=0,len(nums)-1
        while left<=right:
            mid=(left+right)//2
            if nums[mid]<=target: # 找到比target大的第一个数作为left
                left=mid+1
            else:
                right=mid-1
        return left               # 此处返回是left作为右边界

二分法二,三参考负雪明烛,链接:【LeetCode】34. Find First and Last Position of Element in Sorted Array 解题报告(Python & C++)_负雪明烛的博客-CSDN博客

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 ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

来源:力扣(LeetCode)
链接:力扣

题解

二分法一:

class Solution:
    def findMin(self, nums: List[int]) -> int:
        n=len(nums)
        left,right=0,n-1
        while left<=right:
            mid=(left+right)//2
            if nums[mid]>nums[right]:
                left=mid+1
            elif nums[left]<=nums[mid]<=nums[right]: # left,mid,right是按照顺序排列的时候,返回left
                return nums[left]
            else:       # nums[mid]<left:
                right=mid

二分法二:思路类似负雪明烛方法三,传送门在下方。

class Solution:
    def findMin(self, nums: List[int]) -> int:
        n=len(nums)
        if n==1:
            return nums[0]
        left,right=0,n-1
        while nums[left]>nums[right]: # 当子序列也是经过旋转的时候,不断寻找有序的部分
            if right==left+1:         # 当左边界与有边界相邻的时候,返回右边界
                return nums[right]
            mid=(left+right)//2
            if nums[mid]>nums[right]:
                left=mid+1
            else:  # nums[mid]<nums[left]
                right=mid
        return nums[left]

二分法三:参考负雪明烛,传送门在下方。

参考链接:【LeetCode】153. Find Minimum in Rotated Sorted Array 解题报告(Python)_负雪明烛的博客-CSDN博客

162.寻找峰值(中等)

题目要求

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

来源:力扣(LeetCode)
链接:力扣

题解

二分法:参考负雪明烛

class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        n=len(nums)
        if n==1:
            return 0
        left,right=0,n-1
        while left<right:
            mid=(left+right)//2
            if nums[mid]<nums[mid+1]: # 找升序数组,逐渐逼近坡顶
                left=mid+1
            else:                     # nums[mid]>=nums[mid+1]的时候即为坡顶
                right=mid
        return left

参考链接:【LeetCode】162. Find Peak Element 解题报告(Python)_负雪明烛的博客-CSDN博客

4.    寻找两个正序(困难)

题目要求

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

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

来源:力扣(LeetCode)
链接:力扣

题解

第一遍理解错了,搞了个求中值(代码就不放了),第二遍搞成了每个列表的中值再求平均(代码先放这里吧),但是题目是让我们合并数组的中值。干饭去了,明天接着弄。

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:  
        nums1=self.median_array(nums1)
        nums2=self.median_array(nums2)
        nums1.extend(nums2)
        nums1.sort()
        n=len(nums1)
        if n==0:
            return 0
        elif n==1:
            return nums1[0]
        elif n==3:
            return nums1[1]
        else:
            return (nums1[n//2]+nums1[n//2-1])/2

    def median_array(self,num):
        n=len(num)
        if n==0:
            return []
        if n==1:
            return [num[0]]
        mid=n//2
        print(mid)
        if n%2==0:
            return [num[mid-1],num[mid]]
        else:
            return [num[mid]]
        

重新来过

方法一:两个数组合并,掉包排序,根据合并后的数组长度求中位数。

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        nums1.extend(nums2)     # 合并数组
        nums1.sort()            # 排序
        n=len(nums1) 
        if n%2==0:              # 数组长度为偶数个,则返回中间两个数的平均值
            return (nums1[n//2]+nums1[n//2-1])/2
        else:                   # 数组长度为奇数个,则返回中间那个数
            return nums1[n//2]

方法二:

排序

912.排序数组

题目要求

给你一个整数数组 nums,请你将该数组升序排列。

题解&问题

方法一:快排,但是针对有序数组,快排的复杂度也会编程O(n^2),超出时间限制。

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
                   
        def partition(nums,left,right):
            tmp=nums[left]
            while left<right:
                while left<right and nums[right]>=tmp:
                    right-=1
                nums[left]=nums[right]
                while left<right and nums[left]<=tmp:
                    left+=1
                nums[right]=nums[left]
            nums[left]=tmp
            return left

        def quicksort(nums,left,right):
            if left<right:
                mid=partition(nums,left,right)
                quicksort(nums,left,mid-1)
                quicksort(nums,mid+1,right)

        quicksort(nums,0,len(nums)-1)
        return nums

改进

改进思路:针对有序数列倒是快排复杂度提高问题,随机选择初始值从数列的哪一侧开始。

问题:会不会随机的时候选择的刚好是顺序排列的那侧??

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:

        def partition(nums, low, high):
            tmp_idx = random.randint(low, high)                   # 随机选择tmp
            nums[low], nums[tmp_idx] = nums[tmp_idx], nums[low]   # tmp放置到最左边
            tmp = nums[low]                                       # 选取最左边为tmp

            left, right = low, high     # 双指针
            while left < right:                
                while left<right and nums[right] >= tmp:          
                    right -= 1
                nums[left] = nums[right]                            
                while left<right and nums[left] <= tmp:          
                    left += 1
                nums[right] = nums[left]                            
            nums[left] = tmp           
            return left
        
        def quickSort(nums, low, high):
           if low<high:
               mid = partition(nums, low, high)     
               quickSort(nums, low, mid-1)          
               quickSort(nums, mid+1, high)
        
        quickSort(nums, 0, len(nums)-1)         
        return nums

方法二:堆排序

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        #堆排,大根堆
        def sift(nums,low,high):
            i=low
            j=2*i+1
            tmp=nums[low]
            while j<=high:
                if j+1<=high and nums[j+1]>nums[j]:
                    j=j+1
                if tmp<nums[j]:
                    nums[i]=nums[j]
                    i=j
                    j=2*i+1
                else:
                    nums[i]=tmp
                    break
            else:
                nums[i]=tmp
        def heap_sort(nums):
            #建堆
            n=len(nums)
            for i in range((n-1-1)//2,-1,-1):
                sift(nums,i,n-1)
            #交换输出,向下调整
            for j in range(n-1,-1,-1):
                nums[0],nums[j]=nums[j],nums[0]
                sift(nums,0,j-1)
        
        heap_sort(nums)
        return nums

双指针

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

题目要求

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。

来源:力扣

链接:力扣

题解&问题

解题思路:(参考负雪明烛)   双指针:

1.慢指针指向存储位置;

2.快指针找非重复元素位置:元素重复则指针后移,不重复了就赋值。

写法一

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        n=len(nums)
        if n<=1:
            return n
        left,right=0,1                                    # left是不重复数据存放的位置
        while right<n:                 # 在大循环中,right在条件内每次自动+1
            while right<n and nums[left]==nums[right]:    # 如果碰到相同的值,right+1
                right+=1               # 排除重复元素干扰后的新right
            left+=1                    # 大循环中,left后移用于存放下一个不重复数据
            if right<n:
                nums[left]=nums[right] # 满足条件,更新left指向的数值
        return left                    # 此时left所指的位置即为无重复子数组长度

同样思路,写法二

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        n=len(nums)
        if n<=1:
            return n
        left, right = 0, 1
        while right<n:
            if nums[left]!=nums[right]:  # 元素不重复,则赋值
                left+=1
                nums[left]=nums[right]              
            right+=1                     # 元素重复,则right后移
        return left+1

参考链接:【LeetCode】26. Remove Duplicates from Sorted Array 解题报告(Python&C++&Java)_负雪明烛的博客-CSDN博客

注:示例中输出里面的下划线,代表不需要考虑那个元素是什么(因为本题是原地更新数组)。

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

动态规划

53.最大子数组和

题目要求

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

来源:力扣

链接:力扣

解题&问题:

方法一:暴力方法,把以当前数字开头的所有可能的和都存入sum_tmp,一共有len(nums)个sum_tmp。把每个sum_tmp中最大的值存入max_sum,最后返回max_sum的最大值即为所求。

class Solution:
    def maxSubArray(self, nums) :       
        max_sum=[]     # 以每个数开头的最大和
        for i in range(len(nums)):
            a=0
            sum_tmp=[] # 以当前数字开头的所有和的可能
            for j in range(i,len(nums)):
                a+=nums[j]
                sum_tmp.append(a)
            he.append(max(sum_tmp))
        return max(max_sum)

方法二:动态规划(思路来源负雪明烛)

找到(包含当前节点的)与之前节点构成的连续数组的最大和。

1.如果前一个节点的子数组最大和>0,那么当前节点的数组最大和=当前元素+前一节点的数组最大和,即dp[i] = dp[i-1] + nums[i]

2.如果前一个节点的子数组最大和<=0,那么当前节点自己的值就是最大的,即dp[i] = nums[i]。

# 以dp[i]结尾的最大子数组的和
# dp[i] = dp[i-1] + nums[i]   当 nums[i] >= 0
# dp[i] = nums[i]             当 nums[i] < 0

class Solution:
    def maxSubArray(self, nums) :   
        pre,cur=0,0          # 指针从零开始
        max_sum=float("-inf")# 最大子数组和(由于数组内元素可能为负值,所以第一次和负无穷比较)
        for i in range(len(nums)):
            if pre > 0:      # 如果前一个节点的子数组最大和>0,那么当前节点的数组最大和=当前元素+前一节点的数组最大和
                cur+=nums[i]
            else:            # 如果前一个节点的子数组最大和<=0,那么当前节点自己的值就是最大的
                cur=nums[i]
            pre=cur          # 指针后移
            max_sum=max(max_sum,cur)  # 更新最大子数组和
        return max_sum

负雪明烛原文链接:【LeetCode】53. Maximum Subarray 最大子序和 解题报告(Python & C++ & Java)_负雪明烛的博客-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值