leetcode刷题

菜鸡刷题,是记录自己的写题过程,不具备什么参考价值,有空的话会找优秀的解法,暂时以先做出来为准

分治算法

寻找两个有序数组的中位数

4
我觉得似乎没有用分治法

难点在于题目要求时间复杂度为O(log(m+n))
这类题可以转化为求有序数组第k大/小的问题



通过比较两个数组k//2处的数字,可以一下排除一半的查询范围
感谢这位的解法三 参考解法

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        def findKnum(nums1,begin1,m,nums2,begin2,n,k):
            if begin1>=m: return nums2[begin2+k-1]
            if begin2>=n: return nums1[begin1+k-1]
            if k==1:
                return min(nums1[begin1],nums2[begin2])
            p1 = min(begin1 + k//2 -1,m-1)
            p2 = min(begin2 + k//2 -1,n-1)
            if nums1[p1]<nums2[p2]:
                return findKnum(nums1,p1+1,m,nums2,begin2,n,k-(p1-begin1+1))
            else:
                return findKnum(nums1,begin1,m,nums2,p2+1,n,k-(p2-begin2+1))

        m = len(nums1)
        n = len(nums2)
        if (m+n)%2==1: return findKnum(nums1,0,m,nums2,0,n,(m+n)//2+1)
        else: return (findKnum(nums1,0,m,nums2,0,n,(m+n)//2+1)+findKnum(nums1,0,m,nums2,0,n,(m+n-1)//2+1))/2

合并k个链表

23

这里分治解法的思想是两两链表合并,时间复杂度为O(Nlogk)

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:

        def merge2List(l1,l2):
            l = ListNode(-1)
            p = l
            while l1 and l2:
                if l1.val<=l2.val:
                    p.next = l1
                    l1 = l1.next
                else:
                    p.next = l2
                    l2 = l2.next
                p = p.next
            if l1: p.next = l1
            if l2: p.next = l2
            return l.next
        if len(lists)==0:return None
        while len(lists)!=1:
            lists.append(merge2List(lists.pop(0),lists.pop(0)))
        return lists[0]

最大子序和

53
这里分别使用了两种方法:动态规划法和分治法(感谢大神)

分治法的主要思想是最大子序和分为以下三种情况:在左半段里,在右半段里,或者是跨过左右半端,并依次这么分下去,取最大值即可

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        # 这里用的动态规划,在返回值的时候请动脑子应该返回啥
        n = len(nums)
        dp = [0 for i in range(n)]
        dp[0] = nums[0]
        for i in range(1,n):
            dp[i] = max(dp[i-1]+nums[i],nums[i])
        return max(dp)
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        size = len(nums)
        if size == 0:
            return 0
        return self.__max_sub_array(nums, 0, size - 1)

    def __max_sub_array(self, nums, left, right):
        if left == right:
            return nums[left]
        mid = (left + right) >> 1
        return max(self.__max_sub_array(nums, left, mid),
                   self.__max_sub_array(nums, mid + 1, right),
                   self.__max_cross_array(nums, left, mid, right))

    def __max_cross_array(self, nums, left, mid, right):
        # 一定包含 nums[mid] 元素的最大连续子数组的和,
        # 思路是看看左边"扩散到底",得到一个最大数,右边"扩散到底"得到一个最大数
        # 然后再加上中间数
        left_sum_max = 0
        start_left = mid - 1
        s1 = 0
        while start_left >= left:
            s1 += nums[start_left]
            left_sum_max = max(left_sum_max, s1)
            start_left -= 1

        right_sum_max = 0
        start_right = mid + 1
        s2 = 0
        while start_right <= right:
            s2 += nums[start_right]
            right_sum_max = max(right_sum_max, s2)
            start_right += 1
        return left_sum_max + nums[mid] + right_sum_max

作者:liweiwei1419
链接:https://leetcode-cn.com/problems/maximum-subarray/solution/dong-tai-gui-hua-fen-zhi-fa-python-dai-ma-java-dai/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

多数元素

169

这里的思想是把数组看成左右两部分,如果左右两部分众数一样则整个数组的众数就是该数字,如果不一样,分别计算左右众数在整个数组中的个数,选出最大的

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        def findmost(left,right):
            if left==right:
                return nums[left]
            mid = (left+right)>>1
            lmost = findmost(left,mid)
            rmost = findmost(mid+1,right)
            if lmost==rmost: return lmost
            else:
                ln,rn = 0,0
                for i in range(left,right+1):
                    if nums[i]==lmost: ln += 1
                    elif nums[i]==rmost: rn += 1
                return lmost if ln>rn else rmost
        n = len(nums)
        return findmost(0,n-1)

数组中的第K个最大元素

215
这里分别使用了两种方法,分治法和

分治法用了快排中的思想,先找一个数排到适当的位置,根据它是第几个数判断我们要找的数会在它的左右范围内查找

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        def quick_sort(l,r):
            pivot = nums[l]
            i = l
            while l!=r:
                while nums[r]<=pivot and l<r:
                    r -= 1
                while nums[l]>=pivot and l<r:
                    l += 1
                if l<r:
                    nums[l],nums[r] = nums[r],nums[l]
            nums[l],nums[i] = pivot,nums[l]
            return l
        n = len(nums)
        l = 0
        r = n-1
        m = quick_sort(l, r)
        while m!=k-1:
            if m>k-1:
                r = m-1
                m = quick_sort(l,r)
            else:
                l = m+1
                m = quick_sort(l,r)
        return nums[m]
class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        def build_heap(i):
            smallest = i
            l = 2*i + 1
            r = 2*i + 2
            if l<k and nums[i]>nums[l]:
                smallest = l
            if r<k and nums[smallest]>nums[r]:
                smallest = r
            if i!=smallest:
                nums[i],nums[smallest] = nums[smallest],nums[i]
                build_heap(smallest)
        n = len(nums)
        for i in range(k-1,n):
            for j in range(k-1,-1,-1):
                if nums[i]>nums[0]:
                    nums[0],nums[i] = nums[i],nums[0]
                build_heap(j)
        return nums[0]

搜索二维矩阵 II

240

这里的思想是把矩阵分为四个部分,然后如果target小于某个矩阵左上角的值,就排除该矩阵,这里要注意边界条件

class Solution:
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        def search_target(left,right,up,down):
            if left>right or up>down or matrix[up][left]>target: return False
            if left==right and up==down: return matrix[up][left]==target
            if matrix[up][left]==target:return True
            cmid = (left+right)>>1
            rmid = (up+down)>>1
            return search_target(left,cmid,up,rmid) or search_target(cmid+1,right,up,rmid) or search_target(left,cmid,rmid+1,down) or search_target(cmid+1,right,rmid+1,down)
            
        m = len(matrix)
        if m==0: return False
        n = len(matrix[0])
        return search_target(0,n-1,0,m-1)

为运算表达式设计优先级

241

这里的思想是看到一个运算符,就分别计算它的左右两个部分

class Solution:
    def diffWaysToCompute(self, input: str) -> List[int]:
        def cal(x,y,op):
            if op=='+':
                return x+y
            elif op=='-':
                return x-y
            elif op=='*':
                return x*y

        def multi_calculate(s):
            if s.isdigit(): return [int(s)]
            res = []
            for c in range(len(s)):
                if s[c] in ['+','-','*']:
                    for l in multi_calculate(s[:c]):
                        for r in multi_calculate(s[c+1:]):
                            res.append(cal(l,r,s[c]))
            return res
        return multi_calculate(input)

最接近原点的K个点

973

分治的思想用于类似快速排序那样,和数组中的第K个最大元素那题类似

class Solution:
    def kClosest(self, points: List[List[int]], K: int) -> List[List[int]]:
        def distance(p):
            return p[0]**2+p[1]**2

        def quick_sort(left,right):
            i = left
            pivot = points[left]
            while left<right:
                while distance(pivot)<=distance(points[right]) and left<right:
                    right -= 1
                while distance(pivot)>=distance(points[left]) and left<right:
                    left += 1
                if left!=right:
                    points[left],points[right] = points[right],points[left]
            points[left],points[i] = pivot,points[left]
            return left
        
        n = len(points)
        if K>=n: return points
        if K<=0: return []
        l,r = 0,n-1
        k = quick_sort(l,r)
        while k!=K:
            if k>K:
                r = k-1
                k = quick_sort(l,r)
            elif k<K:
                l = k+1
                k = quick_sort(l, r)
        return points[:k]

矩形内船只的数目

1274
在这里插入图片描述
在这里插入图片描述

这里分治法的思想是把完整的海域分成四个部分,分别判断,如果有船则细分,没有则忽略

# """
# This is Sea's API interface.
# You should not implement it, or speculate about its implementation
# """
# class Sea(object):
#    def hasShips(self, topRight: 'Point', bottomLeft: 'Point') -> bool:

# class Point(object):
# 	def __init__(self, x: int, y: int):
# 		self.x = x
# 		self.y = y

class Solution(object):
    def countShips(self, sea: 'Sea', topRight: 'Point', bottomLeft: 'Point') -> int:
        def find_ship(topRight,bottomLeft):
            left,right,up,down = bottomLeft.x,topRight.x,topRight.y,bottomLeft.y
            if left>right or up<down or not sea.hasShips(topRight,bottomLeft): return 0
            if left==right and up==down: return 1
            cmid = (left+right)>>1
            rmid = (up+down)>>1
            return find_ship(Point(cmid,up),Point(left,rmid+1))+find_ship(topRight,Point(cmid+1,rmid+1))+find_ship(Point(cmid,rmid),bottomLeft)+find_ship(Point(right,rmid),Point(cmid+1,down))
        return find_ship(topRight,bottomLeft)

双指针

子序列!=子串 (子序列可以是由里面的字母按顺序但可以不连续的组成的部分)

无重复的最长子串

3

主要的思想就是用两个指针,分别表示子串的起始和结束位置

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        w = {}
        l,r = 0,0
        n = len(s)
        count = 0
        while r<n:
            if s[r] not in w.keys() or w[s[r]]<l:
                w[s[r]] = r
            else:
                l = w[s[r]]+1    
                w[s[r]] = r
            count = max(count,r-l+1)
            r += 1
        return count

三数之和

15

用排序,用两个指针分别指向数组的头和尾,然后根据结果的大小进行移动

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 先排序,O(NlogN),再用两个指针分别指向左右,根据和的大小进行移动,这里需要注意优化,比如输入的列表长度小于3且最大的一项都小于0则无需向下排,另外如果选的最小项>0也无需排,相等的值可以跳过
        nums.sort()
        n = len(nums)
        res = []
        if n<3 or nums[-1]<0: return res
        for i in range(n-2):
            l,r = i+1,n-1
            if nums[i]>0:
                return res
            if i>0 and nums[i]==nums[i-1]:
                continue
            while l<r:
                s = nums[i]+nums[l]+nums[r]
                if s>0:
                    r -= 1

                elif s<0:
                    l += 1
                else:
                    res.append([nums[i],nums[l],nums[r]])
                    while l<r and nums[l]==nums[l+1]:
                        l += 1
                    while l<r and nums[r]==nums[r-1]:
                        r -= 1
                    l += 1
                    r -= 1
        return res

接雨水

42

分别用了动态规划法和双指针法
其中双指针法主要思路就是在首尾各有一个指针,然后按照条件进行移动

class Solution:
    def trap(self, height: List[int]) -> int:
        # 这里用了动态规划的思想,如果按常规的方法,应该是循环找每一列的左边最高列和右边最高列,这样会有很多重复的数据,所以只需把它们保存起来即可
        # n = len(height)
        # if n<3: return 0
        # max_left = [0 for _ in range(n)]
        # max_right = [0 for _ in range(n)]
        # for i in range(n):
        #     if i==0: 
        #         max_left[i] = height[i]
        #     else:
        #         max_left[i] = max(max_left[i-1],height[i])
        # # print(max_left)
        # for i in range(n-1,-1,-1):
        #     if i==n-1: 
        #         max_right[i] = height[i]
        #     else:
        #         max_right[i] = max(max_right[i+1],height[i])
        # # print(max_right)
        # ans = 0
        # for i in range(n):
        #     if height[i]<max_left[i] and height[i]<max_right[i]:
        #         ans += min(max_left[i],max_right[i])-height[i]
        # return ans

        # 这个节约了一点空间,可以不用数组表示左边最大值
        # n = len(height)
        # if n<3: return 0
        # max_left = 0
        # max_right = [0 for _ in range(n)]
        # for i in range(n-1,-1,-1):
        #     if i==n-1: 
        #         max_right[i] = height[i]
        #     else:
        #         max_right[i] = max(max_right[i+1],height[i])
        # # print(max_right)
        # ans = 0
        # for i in range(n):
        #     max_left = max(max_left,height[i])
        #     if height[i]<max_left and height[i]<max_right[i]:
        #         ans += min(max_left,max_right[i])-height[i]
        # return ans
class Solution:
    def trap(self, height: List[int]) -> int:
        # 这是用了双指针,但是对于它的逻辑我还不是那么熟悉,还需要反复看,但是空间复杂度下降为常数了
        n = len(height)
        if n<3:return 0
        left,right = 1,n-2
        max_left,max_right = 0,0
        ans = 0
        for i in range(1,n-1):
            if height[left-1]<height[right+1]:
                max_left = max(max_left,height[left-1])
                if height[left]<max_left:
                    ans += max_left-height[left]
                left += 1
            else:
                max_right = max(max_right,height[right+1])
                if height[right]<max_right:
                    ans += max_right-height[right]
                right -= 1
        return ans

盛最多水的容器

11

有指向首尾的两个指针,移动较短的那根才有可能盛水量变多

class Solution:
    def maxArea(self, height: List[int]) -> int:
        # 这个就是使用两个指针,分别指向头和尾,由于大小取决于两者中最短的线,移动较短的线才有可能得到更大的面积
        n = len(height)
        l,r = 0,n-1
        maxarea = 0
        while l<r:
            maxarea = max(maxarea,min(height[l],height[r])*(r-l))
            if height[l]<height[r]:
                l += 1
            else:
                r -= 1
        return maxarea

最接近的三数之和

16

和三数之和那题类似,先排序,再用两个指针找

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        # 主要还是和三数之和类似的方法,先排序,再设置两个指针找
        n = len(nums)
        nums.sort()
        if n<3: return
        minsum = nums[0]+nums[1]+nums[2]
        for i in range(n-2):
            l,r = i+1,n-1
            while l<r:
                s = nums[i]+nums[l]+nums[r]
                minsum = s if abs(target-s)<abs(target-minsum) else minsum
                if s<target:
                    l += 1
                elif s>target:
                    r -= 1
                else:
                    return target
        return minsum

删除排序数组中的重复项

26

设置快慢两个指针,不相等时就覆盖

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        # 还是双指针的思想,一个快一个慢然后比较并赋值,应该是O(N)
        n = len(nums)
        if n<2:return n
        p,q=0,1
        while q<n:
            if nums[p]!=nums[q]:
                p += 1
                nums[p] = nums[q]
            q += 1
        return p+1

四数之和

18

和三数之和类似

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        # O(N^3) 基本思路同两数和三数相加一样
        nums.sort()
        n = len(nums)
        res = []
        if n < 4: return res
        for i in range(n-3):
            if i>0 and nums[i]==nums[i-1]: continue
            for j in range(i+1,n-2):
                if j>i+1 and nums[j]==nums[j-1]: continue
                l,r = j+1,n-1
                while l<r:
                    s = nums[i]+nums[j]+nums[l]+nums[r]
                    if s==target:
                        res.append([nums[i],nums[j],nums[l],nums[r]])
                        while l<r and nums[l]==nums[l+1]:
                            l += 1
                        while l<r and nums[r]==nums[r-1]:
                            r -=1
                        l += 1
                        r -= 1
                    elif s>target:
                        r -= 1
                    else:
                        l += 1
        return res

合并两个有序数组

88

两个数组分别从后往前比较,然后从后向前放置合并元素

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.
        """
        cur = m+n-1
        i,j = m-1,n-1
        while i>=0 and j>=0 and cur>=0:
            if nums1[i]>nums2[j]:
                nums1[cur] = nums1[i]
                i -= 1
            else:
                nums1[cur] = nums2[j]
                j -= 1
            cur -= 1
        while j>=0:
            nums1[cur] = nums2[j]
            j -= 1
            cur -= 1

分隔链表

86

似乎可以省掉一个变量,不用cur直接用head,但是基本思想就是找到要插入的位置和要插入的元素

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def partition(self, head: ListNode, x: int) -> ListNode:
        pre = ListNode(-1)
        pre.next = head
        cur = head
        h = pre # 插入到它后面
        prehead = pre 
        while cur:
            while h and h.next and (h.next).val<x:
                h = h.next
            pre = h
            cur = h.next
            while cur and cur.val>=x:
                cur = cur.next
                pre = pre.next
            if h and cur:
                pre.next = cur.next
                cur.next = h.next
                h.next = cur
        return prehead.next

删除链表的倒数第N个节点

19

是用一个指针先走N步,然后另一个指针从头一起走,这样就可以指向倒数第N个节点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        prehead = ListNode(-1)
        prehead.next = head
        pre = prehead
        f = head
        while n>0 and f:
            f = f.next
            n -= 1
        while f and pre and head:
            f = f.next
            pre = pre.next
            head = head.next
        pre.next = head.next
        return prehead.next

两个数组的交集

349

按双指针写,用了排序,所以时间复杂度比较搞

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        res = []
        nums1.sort()
        nums2.sort()
        i,j = 0,0
        m,n = len(nums1),len(nums2)
        while i<m and j<n:
            if nums1[i]>nums2[j]:
                j += 1
            elif nums1[i]<nums2[j]:
                i += 1
            else:
                res.append(nums1[i])
                i += 1
                while i<m and nums1[i]==nums1[i-1]:
                    i += 1
                j += 1
                while j<n and nums2[j]==nums2[j-1]:
                    j += 1
        return res

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

167

非常简单的一题,和两数之和一样,对于排序数组是首尾两个指针,根据和大小分别移动两个指针

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        n = len(numbers)
        l,r = 0,n-1
        while l<r:
            numsum = numbers[l]+numbers[r]
            if numsum==target:
                return [l+1,r+1]
            elif numsum>target:
                r -= 1
            else:
                l += 1
        return []

串联所有单词的字串

30

有点滑动窗口的样子

class Solution:
    def findSubstring(self, s: str, words: List[str]) -> List[int]:
        res = []
        m = len(words) # 单词个数
        if m==0: return []
        n = len(words[0]) # 每个单词的长度
        ns = len(s)
        l,r = 0,m*n
        words.sort()
        while r<=ns:
            m_words = []
            for i in range(m):
                m_words.append(s[l+i*n:l+(i+1)*n])
            if sorted(m_words)==words: res.append(l)
            l += 1
            r += 1
        return res

寻找重复数

287

思想是类似二分法那样,计算小于等于中间数的个数,如果大于一定的数目,就说明重复数在那个范围里

class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        n =len(nums)
        left,right = 1,n-1
        while left<right:
            mid = (left+right)>>1
            cnt = 0
            for num in nums:
                if num<=mid:
                    cnt += 1
            if cnt>mid:
                right = mid
            else:
                left = mid+1
        return left

实现Strstr()

28

很简单的一题,就是类似滑动窗口的思想

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        m = len(haystack)
        n = len(needle)
        l,r = 0,n
        while r <= m:
            if haystack[l:r]==needle:
                return l
            l += 1
            r += 1
        return -1

颜色分类

75

我觉得这题能这么写是因为只有三类,它的普适写法应该是先扫一边计算每个元素个数再重新产生该列表,如果用双指针的话就分别指向0和2的位置,然后扫描的元素符合条件,就和相应位置的元素交换

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n = len(nums)
        zero,two = 0,n-1
        cur = 0
        while cur<=two:
            if nums[cur]==0:
                nums[cur],nums[zero] = nums[zero],nums[cur]
                zero += 1
                cur += 1
            elif nums[cur]==2:
                nums[cur],nums[two] = nums[two],nums[cur]
                two -= 1
            else:
                cur += 1

移除元素

27

首尾两个指针,然后用尾部的非target替换首部target

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 首尾两个指针,找到想要的值就替换
        n = len(nums)
        if n<1: return n
        p,q = 0,n-1
        while p<q:
            while p<q and nums[p]!=val:
                p += 1
            while p<q and nums[q]==val:
                q -=1
            if p<q:
                nums[p] = nums[q]
                p += 1
                q -= 1
        return p+1 if p==q and nums[p]!=val else p

反转字符串

344

首尾指针交换

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        n = len(s)
        l,r = 0,n-1
        while l<r:
            s[l],s[r] = s[r],s[l]
            l += 1
            r -= 1

环形链表

141

快慢两个指针,相遇即有环

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        slow = head
        if head and head.next and (head.next).next:
            fast = (head.next).next
        else:
            return False
        while slow and slow.next and fast and fast.next:
            if slow==fast:
                return True
            slow = slow.next
            fast = (fast.next).next
        return False

回文链表

234

先找中间位置,然后将后半段逆序,然后分别比较前后半段

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        cnt = 0
        p = head
        while p:
            cnt += 1
            p = p.next
        if cnt<=1: return True
        p = head
        half_cnt = (cnt-1)//2
        while half_cnt>0:
            half_cnt -= 1
            p = p.next
        pre = p.next
        cur = pre.next
        while cur:
            pre.next = cur.next
            cur.next = p.next
            p.next = cur
            cur = pre.next
        half_cnt = cnt//2-1
        p1 = head
        p2 = p.next
        while half_cnt>=0:
            if p1.val!=p2.val:
                return False
            half_cnt -= 1
            p1 = p1.next
            p2 = p2.next
        return True

移动零

283

也是很简单的一题,两个指针,把非零的元素按位置顺序放入数组中

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n = len(nums)
        i,j = 0,0
        while j<n:
            if nums[j]!=0:
                nums[i] = nums[j]
                i += 1
            j += 1
        while i<n:
            nums[i] = 0
            i += 1

长度最小的子数组

209

类似滑动窗口的思想

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        n = len(nums)
        if sum(nums)<s: return 0
        l,r = 0,0
        minlen = n
        valsum = nums[0]
        if valsum>s:
            return 1
        while r<n:
            if valsum<s:
                r += 1
                if r<n:
                    valsum += nums[r]
            else:
                minlen = min(minlen,r-l+1)
                valsum -= nums[l]
                l += 1
        return minlen

旋转链表

61

主要是找到旋转位置,然后放到头部,有点像找到链表倒数第k个元素

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def rotateRight(self, head: ListNode, k: int) -> ListNode:
        cnt = 0
        p = head
        while p:
            cnt += 1
            p = p.next
        if cnt<=1: return head
        prehead = ListNode(-1)
        prehead.next = head
        k = k%cnt
        if k==0: return head
        q = head
        tail = prehead
        while k>=0:
            q = q.next
            tail = tail.next
            k -= 1
        while q:
            head = head.next
            q = q.next
            tail = tail.next
        tail.next = prehead.next
        prehead.next = head.next
        head.next = None
        return prehead.next

反转字符串中的元音字母

345

分别从前后查找需要交换的元素

class Solution:
    def reverseVowels(self, s: str) -> str:
        n = len(s)
        l,r = 0,n-1
        vowel = ['a','e','i','o','u']
        s_list = list(s)
        while l<r:
            while l<r and s_list[l].lower() not in vowel:
                l += 1
            while l<r and s_list[r].lower() not in vowel:
                r -= 1
            if l<r:
                s_list[l],s_list[r] = s_list[r],s_list[l]
                l += 1
                r -= 1
        return ''.join(s_list)

环形链表 II

142

先像之前的一样判断有无环,然后一个从head开始,一个从相遇点开始,再一次相遇时就为环的起点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        slow,fast = head,head
        flag = False
        while slow and slow.next and fast and fast.next and (fast.next).next:
            slow = slow.next
            fast = (fast.next).next
            if slow== fast:
                flag = True
                break
        if not flag:
            return None
        p = head
        while p!=slow:
            p = p.next
            slow = slow.next
        return p

验证回文串

125

首尾指针比较

class Solution:
    def isPalindrome(self, s: str) -> bool:
        n = len(s)
        l,r = 0,n-1
        while l<r:
            while l<r and not s[l].isalnum():
                l += 1
            while l<r and not s[r].isalnum():
                r -= 1
            if l<r:
                if s[l].lower()!=s[r].lower():
                    return False
                l += 1
                r -= 1
        return True

两个数组的交集 II

350

很简单第一题,排序后比较

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        nums1.sort()
        nums2.sort()
        m = len(nums1)
        n = len(nums2)
        p1,p2 = 0,0
        res = []
        while p1<m and p2<n:
            if nums1[p1]==nums2[p2]:
                res.append(nums1[p1])
                p1 += 1
                p2 += 1
            elif nums1[p1]>nums2[p2]:
                p2 += 1
            else:
                p1 += 1
        return res

乘积小于K的子数组

713

这个有参考别人的方式,我自己写的不知道为什么超时了,注意这里res的算法,有点巧妙

class Solution:
    def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
        n = len(nums)
        if n==0: return 0
        res = 0
        l,r = 0,0
        multi = 1
        while l<n:
            while r<n and multi*nums[r]<k:
                multi *= nums[r]
                r += 1
            if l<r:
                res += r-l
                multi //= nums[l]
                l += 1
            else:
                l += 1
                r = l
                multi = 1
        return res

通过删除字母匹配到字典里最长单词

524

这里我先给字典按长度和字典序排列,然后分别在字符串中查找字典中的对应字符串

class Solution:
    def findLongestWord(self, s: str, d: List[str]) -> str:
        d.sort(key=lambda x: [-len(x), x])
        # print(d)
        for ds in d:
            i,j = 0,0
            while i<len(s) and j<len(ds):
                if s[i]==ds[j]:
                    j += 1
                i += 1
            if j==len(ds): return ds
        return ''

有序转化数组

360
在这里插入图片描述

先找出曲线最低或最高点,然后用两个指针从此点分别向左向右移动

class Solution:
    def sortTransformedArray(self, nums: List[int], a: int, b: int, c: int) -> List[int]:
        n = len(nums)
        if n==0: return []
        res = []
        mindex = 0
        if a!=0:
            mid = -b/(2*a)
            d = abs(nums[0]-mid)
            for i in range(1,n):
                if abs(nums[i]-mid)<d:
                    d = abs(nums[i]-mid)
                    mindex = i
        l,r = mindex-1,mindex
        while l>=0 and r<n:
            if abs(nums[l]-mid)<abs(nums[r]-mid):
                res.append(a*(nums[l])**2+b*nums[l]+c)
                l -= 1
            else:
                res.append(a*(nums[r])**2+b*nums[r]+c)
                r += 1
        while l>=0:
            res.append(a*(nums[l])**2+b*nums[l]+c)
            l -= 1
        while r<n:
            res.append(a*(nums[r])**2+b*nums[r]+c)
            r += 1
        return res if a>0 or (a==0 and b>0) else reversed(res)

数组中的K-diff数对

532

先排序再用双指针找符合条件的元素

class Solution:
    def findPairs(self, nums: List[int], k: int) -> int:
        nums.sort()
        n = len(nums)
        if n<2: return 0
        l,r = 0,1
        res = 0
        while r<n:
            m = nums[r]-nums[l]
            if m==k:
                res += 1
                l += 1
                while l<n and nums[l]==nums[l-1]:
                    l += 1
                while r<n and nums[r]==nums[r-1]:
                    r += 1
                if l==r:
                    r = l+1
            elif m<k:
                r += 1
            else:
                l += 1
                if l==r:
                    r = l+1
        return res

字符串的排列

567

滑动窗和字典计数的方式

class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        m = len(s1)
        n = len(s2)
        if m>n: return False
        s1_dict = {}
        for c in s1:
            s1_dict[c] = s1_dict.get(c,0)+1
        l,r = 0,m-1
        s2_dict = {}
        for i in range(m):
            s2_dict[s2[i]] = s2_dict.get(s2[i],0)+1
        while r<n:
            if s1_dict==s2_dict:
                return True
            s2_dict[s2[l]] -= 1
            if s2_dict[s2[l]]==0: s2_dict.pop(s2[l])
            l += 1
            r += 1
            if r<n:
                s2_dict[s2[r]] = s2_dict.get(s2[r],0)+1
        return False

至多包含两个不同字符的最长子串

159
在这里插入图片描述

滑动窗口的思想

class Solution:
    def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int:
        pos = {}
        n = len(s)
        l,r = 0,0
        maxlen = 0
        while r<n:
            # print('l:',l)
            # print('r:',r)
            if s[r] not in pos.keys() and len(pos)==2:
                    p1,p2 = pos.items()
                    maxlen = max(maxlen,r-l)
                    l = min(p1[1],p2[1])+1
                    pos.pop(p1[0]) if p1[1]<p2[1] else pos.pop(p2[0])
            pos[s[r]] = r
            r += 1
        maxlen = max(maxlen,r-l)
        return maxlen

较小的三数之和

259
在这里插入图片描述

先排序,然后首尾指针,按照条件进行移动,注意这里符合条件的处理方式

class Solution:
    def threeSumSmaller(self, nums: List[int], target: int) -> int:
        nums.sort()
        n = len(nums)
        if n<3: return 0
        res = 0
        for i in range(n-2):
            t = target-nums[i]
            l,r = i+1,n-1
            while l<r:
                m = nums[l]+nums[r]
                if m<t:
                    res += r-l
                    l += 1
                else:
                    r -= 1
        return res

最大连续1的个数 II

487
在这里插入图片描述

从头开始的两个指针

class Solution:
    def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
        n = len(nums)
        l,r = 0,0
        is_change = False # 判断是否已经转化过一次
        c_index = 0
        res = 0
        while r<n:
            if nums[r]==0:
                if not is_change:
                    is_change = True
                    c_index = r
                else:
                    res = max(res,r-l)
                    is_change = False
                    l = c_index+1
                    r -= 1
            r += 1
        res = max(res,r-l)
        return res

划分字母区间

763

应该算是合并子区间的问题,好像没有用到双指针

class Solution:
    def partitionLabels(self, S: str) -> List[int]:
        def merge_intervals(a):
            n = len(a)
            i,j = 0,1
            while i<len(a) and j<len(a):
                if a[i][0]<a[j][0]<a[i][1]:
                    a[i][1] = max(a[i][1],a[j][1])
                    a.pop(j)
                else:
                    i += 1
                    j = i+1

        pos = {}
        res = []
        n = len(S)
        for i in range(n):
            if S[i] not in pos:
                pos[S[i]] = [i,i]
            else:
                pos[S[i]][1] = i
        # print(pos)
        pos_list = list(pos.values())
        # print(pos_list)
        merge_intervals(pos_list)
        for i in range(len(pos_list)):
            res.append(pos_list[i][1]-pos_list[i][0]+1)
        # print(pos_list)
        return res

安排工作以达到最大收益

826

这里是参考别人的,写得比我原先的简洁很多,这里有几个坑,一个是可能难度小的收益大,所以可以把最好收益存下来

class Solution:
    def maxProfitAssignment(self, difficulty: List[int], profit: List[int], worker: List[int]) -> int:
        jobs = list(zip(difficulty, profit))
        jobs.sort()
        ans = i = best = 0
        for skill in sorted(worker):
            while i < len(jobs) and skill >= jobs[i][0]:
                best = max(best, jobs[i][1])
                i += 1
            ans += best
        return ans

独特字符串

828

这也是参考别人的,写的很精妙,思想就是每个字母分别看在哪些子串中可以作为独特字符
在这里插入图片描述

class Solution:
    def uniqueLetterString(self, S: str) -> int:
        index = collections.defaultdict(list)
        for i, c in enumerate(S):
            index[c].append(i)
        print(index)
        n = len(S)
        res = 0
        for A in index.values():
            A = [-1] + A + [n]
            for i in range(1,len(A)-1):
                res += (A[i] - A[i-1]) * (A[i+1] - A[i])
        return res%(10**9+7)

比较含退格的字符串

844

这里用写的,没有用双指针

class Solution:
    def backspaceCompare(self, S: str, T: str) -> bool:
        def get_str(s):
            stack = []
            n = len(s)
            for c in s:
                if c=='#':
                    if stack:
                        stack.pop()
                else:
                    stack.append(c)
            return ''.join(stack)
        return get_str(S)==get_str(T)

数组中的最长山脉

845

左右指针,顺着规律找山脉

class Solution:
    def longestMountain(self, A: List[int]) -> int:
        n = len(A)
        l,r=0,0
        res = 0
        while r<n:
            for i in range(l,n-1):
                if A[i+1]>A[i]:
                    l = i
                    break
                elif i==n-2:
                    l = n-1
            r = l+1
            is_down = False
            while r<n and A[r]>A[r-1]:
                r += 1
            if r<n and A[r]==A[r-1]:
                l = r
                continue
            while r<n and A[r]<A[r-1]:
                is_down = True
                r += 1
            if is_down:
                res = max(res,r-l)
                l = r-1
        return res

救生艇

881

这个也是参考别人的答案,一个重的搭配目前最轻的,不行的话就一个人搭船,我在这题走了很多弯路,我希望找到一个体重和符合要求且是最大的,完全没必要

class Solution:
    def numRescueBoats(self, people: List[int], limit: int) -> int:
        people.sort()
        n = len(people)
        res = 0
        l,r = 0,n-1
        while l<=r:
            res += 1
            if people[l]+people[r]<=limit:
                l += 1
            r -= 1
        return res

水果成篮

904

这个和159题-至多包含两个不同字符的最长子串 非常相似

class Solution:
    def totalFruit(self, tree: List[int]) -> int:
        fruit = {}
        n = len(tree)
        l,r = 0,0
        maxlen = 0
        while r<n:
            if len(fruit)==2 and tree[r] not in fruit.keys():
                p1,p2 = fruit.items()
                maxlen = max(maxlen,r-l)
                l = min(p1[1],p2[1])+1
                fruit.pop(p1[0]) if p1[1]<p2[1] else fruit.pop(p2[0])
            fruit[tree[r]] = r
            r += 1
        maxlen = max(maxlen,r-l)
        return maxlen

三数之和的多种可能

923

这里除了和之前三数之和那题类似,还多了一个计数步骤

class Solution:
    def threeSumMulti(self, A: List[int], target: int) -> int:
        def get_choice(n,x):  # 这里是计算从n个数取x个数有多少种方式
            if n<x: return 0
            if n==x: return 1
            if x==1: return n
            a,b = 1,1
            for i in range(x):
                a *= (n-i)
                b *= (i+1)
            return a//b
        cnt = {}
        A_list = []
        for num in A:
            if num not in cnt.keys():
                A_list.append(num)
            cnt[num] = cnt.get(num,0)+1
        A_list.sort()
        n = len(A_list)
        ans = 0
        for i in range(n):
            l,r = i,n-1
            while l<=r:
                # print('i,l,r:',i,l,r)
                m = A_list[i]+A_list[l]+A_list[r]
                if m==target:
                    c = {}
                    c[A_list[i]] = c.get(A_list[i],0)+1
                    c[A_list[l]] = c.get(A_list[l],0)+1
                    c[A_list[r]] = c.get(A_list[r],0)+1
                    res = 1
                    for j in c.keys():
                        res *= get_choice(cnt[j],c[j])
                    ans += res
                    l += 1
                    r -= 1
                elif m<target:
                    l += 1
                else:
                    r -= 1
        return ans%(10**9+7)

长按键入

925

很简单的一题,主要是在typed中找有无name匹配即可

class Solution:
    def isLongPressedName(self, name: str, typed: str) -> bool:
        m = len(name)
        n = len(typed)
        i,j = 0,0
        while i<m and j<n:
            if name[i]==typed[j]:
                i += 1
            j += 1
        return False if i<m else True

有序数组的平方

977

很简单的一题

class Solution:
    def sortedSquares(self, A: List[int]) -> List[int]:
        ans = [x*x for x in A]
        ans.sort()
        # 或者将A直接平方,然后通过首尾两个指针放到新列表的相应位置
        return ans

三个有序数组的交集

1213
在这里插入图片描述

这题也比较简单,主要是移动指针

class Solution:
    def arraysIntersection(self, arr1: List[int], arr2: List[int], arr3: List[int]) -> List[int]:
        n1,n2,n3 = len(arr1),len(arr2),len(arr3)
        i,j,k = 0,0,0
        ans = []
        while i<n1 and j<n2 and k<n3:
            if arr1[i]==arr2[j]==arr3[k]:
                ans.append(arr1[i])
                i += 1
                j += 1
                k += 1
            elif arr1[i]<arr2[j] or arr1[i]<arr3[k]:
                i += 1
            elif arr2[j]<arr1[i] or arr2[j]<arr3[k]:
                j += 1
            elif arr3[k]<arr1[i] or arr3[k]<arr2[j]:
                k += 1
        return ans

最大连续1的个数 III

1004

和之前最大连续1的个数类似,别忘了考虑K为0的情况

class Solution:
    def longestOnes(self, A: List[int], K: int) -> int:
        n = len(A)
        l,r = 0,0
        res = 0
        zero_list = []
        while r<n:
            if A[r]==0:
                if len(zero_list)==K:
                    res = max(res,r-l)
                    if zero_list:
                        l = zero_list.pop(0)+1
                    else:
                        l = r+1
                if K!=0:
                    zero_list.append(r)
            r += 1
        res = max(res,r-l)
        return res

大样本统计

1093

没用到双指针思想

class Solution:
    def sampleStats(self, count: List[int]) -> List[float]:
        n = len(count)
        minval,maxval = n-1,0
        cnt = 0
        numsum = 0
        mostcnt,mostval = 0,0
        for i in range(n):
            if count[i]>0:
                minval = min(minval,i)
                maxval = max(maxval,i)
                cnt += count[i]
                numsum += i*count[i]
                if count[i]>mostcnt:
                    mostcnt = count[i]
                    mostval = i
        mid = cnt/2
        midval1,midval2 = n,n
        m = 0
        for i in range(n):
            m += count[i]
            if m>=mid:
                midval1 = min(midval1,i)
            if m>=mid+1:
                midval2 = min(midval2,i)
                break
        midval = midval1 if cnt%2==1 else (midval1+midval2)/2
        return [minval,maxval,numsum/cnt,midval,mostval]

区间列表的交集

986

按照条件进行移动指针

class Solution:
    def intervalIntersection(self, A: List[List[int]], B: List[List[int]]) -> List[List[int]]:
        m = len(A)
        n = len(B)
        i,j = 0,0
        ans = []
        while i<m and j<n:
            if B[j][0]>A[i][1]:
                i += 1
            elif A[i][0]>B[j][1]:
                j += 1
            else:
                if A[i][0]<=B[j][0]<=A[i][1]:
                    ans.append([B[j][0],min(A[i][1],B[j][1])])
                elif B[j][0]<=A[i][0]<=B[j][1]:
                    ans.append([A[i][0],min(A[i][1],B[j][1])])
                if A[i][1]<B[j][1]:
                    i += 1
                else:
                    j += 1
        return ans

统计「优美子数组」

1248

把奇数的位置存起来,需要奇数外的偶数不会影响结果,所以只需要乘积计算包含偶数的各个情况

class Solution:
    def numberOfSubarrays(self, nums: List[int], k: int) -> int:
        n = len(nums)
        odd = []
        for i in range(n):
            if nums[i]%2==1:
                odd.append(i)
        odd = [-1] + odd + [n]
        # print(odd)
        m = len(odd)
        ans = 0
        for i in range(k,m-1):
            ans += (odd[i-k+1]-odd[i-k])*(odd[i+1]-odd[i])
        return ans

和相同的二元子数组

930

这是把需要的数记录下来,计算包含需要数的范围数目,只要前后无影响的数目个数相乘即可,和前面的思想很像,这里就是把1都记录下来

class Solution:
    def numSubarraysWithSum(self, A: List[int], S: int) -> int:
        def get_num(x):
            ans = 0
            for i in range(x):
                ans += x-i
            return ans
        n = len(A)
        ans = 0
        if sum(A)<S or n<1: return 0
        pos = []
        for i in range(n):
            if A[i]==1:
                pos.append(i)
        pos = [-1] + pos + [n]
        m = len(pos)
        if S!=0:
            for i in range(S,m-1):
                ans += (pos[i-S+1]-pos[i-S])*(pos[i+1]-pos[i])
        else:
            for i in range(1,m):
                ans += get_num(pos[i]-pos[i-1]-1)
        return ans

未完成的part

在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值