leetcode总结

二分法

704.二分法查找(找到目标值,不在返回-1)

看到while(left<right)不表示搜索区间为[左闭右开],这一点没有根据,
只看到while(left<right)里的<,不能说明右边界不能取到,
在区间里有偶数个元素的时候,mid = (left + right) / 2只能取到位于左边的中间数
,要想取到位于右边的中间数,就要在括号里加1.之所以要取右边的中间数是因为,
偶数的时候,右边的中间数能把搜索区间缩小。
重点:
写成while(left < right) ,退出循环的时候有 left == right 成立,好处是:
不用判断应该返回 left 还是 right。
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        l = 0
        r = len(nums)-1
        while l < r:
            mid = (l + r + 1)//2
            if nums[mid] == target:
                return l
            elif target < nums[mid]:
                r = mid -1
             else:
                 l = mid + 1
        return -1
 这里会显示有错,while 没有取=,没有通过
               

278.第一个错误的版本  

  class Solution:      
    def firstBadVersion(self, n):
        l, r = 1, n-1
        #这里应该是 l <= r 才能使l, r逼近同一个值
        while l <= r:
            mid = (l + r + 1) // 2
            if isBadVersion(mid):
                #如果说该mid是错误版本,那么应该向前查找
                r = mid - 1
            else:
                #如果说该mid是正确版本,那么应该向后查找
                l = mid + 1
        #最后会逼近到第一个错误版本号l
        return l 

35.搜索插入的位置(找到目标值,并返回索引,不在里面就插入)

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        l = 0
        r = len(nums) - 1
        while l <= r:
            mid = (l + r  + 1)//2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                l = mid + 1
            else:
                r = mid - 1
        return l
和上上一题很像,上上一题不在的时候返回-1,这里选到最后没有找到,就在最后选到的地方插入,由于左右都是一样的,因为重合了,所以返回哪个都一样

双指针

977.有序数组的平方,给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

由于这些数字是有序的,
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        n = len(nums)
        ans = [0] * n  #构建同样长度的0数组,存放数据
        # 从两端开始遍历, 找到平方最大元素放到数组末尾,始终将两端的乘方相比较,放到新数组的最后一个
        i, j, pos = 0, n - 1, n - 1
        while i <= j:
            if nums[i] * nums[i] > nums[j] * nums[j]:
                ans[pos] = nums[i] * nums[i]
                i += 1
            else:
                ans[pos] = nums[j] * nums[j]
                j -= 1
            pos -= 1
        
        return ans

##还有一个最简单的方法是用python的内置函数直接sort

189.轮转数组

轮转数组也有最简单的python方法,当轮转的长度为数组长度的整数倍时相当于没有动,这里用到切片操作
简写就是
        n = len(nums)
        k = k % n
        nums[:] = nums[n - k:] + nums[:n - k]    #nums[:]表示里面所有的元素

283.移动零;将0全部移动到末尾,同时保持非0元素的位置。不能拷贝额外的数组,必须在原数组上操作,并且减少操作次数。

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        # l = 0    #这里需要快慢指针  不是左右指针
        # r = len(nums) - 1
        # while l < = r:
        #     if nums[l] == 0:
        n = len(nums)
        left = right = 0 # 初始化左指针和右指针均指向列表的开头
        while right < n: #右指针不为0就将左右互换,有指针为0就向前移动一个
            if nums[right] != 0: 
                nums[left],nums[right] = nums[right],nums[left] #当没有遇见0的时候换了等于没换
                left += 1
            right += 1   #这里如果右边为0就向前移动一个

167.两数之和,输入有效的数组

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        l = 0
        r = len(numbers) - 1
        while l <= r:
            if numbers[l] + numbers[r] == target:
                return [l+1,r+1]
            elif numbers[l] + numbers[r] < target:
                l += 1
            else:
                r -= 1
     #这个太简单。又是偷懒模式,最后要求返回指定的索引,明天开始,不能只做简单提了

344.反转字符串

easy:

        left,right = 0,len(s)-1
        while left < right:
            s[left],s[right] = s[right],s[left]
            left += 1
            right -= 1
交换然后都向中间挪

557.反转字符串中的单词3,注意是字符串的单词,python内置函数真实yyds,再次作弊

class Solution(object):
    def reverseWords(self, s):
        return " ".join(word[::-1] for word in s.split(" "))

#先空格分割,然后遍历分割之后的列表,对列表里面的每个元素(字符串)逆操作,之后join合并

876.链表的中间节点,

给定一个头结点为 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点

开始均指向链表头节点,然后每次快节点走两步,慢指针走一步,直至快指针指向 null,此时慢节点刚好来到链表的下中节点。
class Solution:
    def middleNode(self, head: ListNode) -> ListNode:
        slow = fast = head
        while fast and fast.next: # 前者是偶数长度终止条件,后者是奇数长度终止条件
            slow = slow.next # 移动一步
            fast = fast.next.next # 移动两步
        return slow

19.删除链表的倒数第n个节点

在原有的链表前面加上一个哑节点,这里设置两个指针,

哑结点的好处在于,因为这里我们是要删除一个结点,所以我们可以定位到被删除结点的前置结点,然后将前置结点的后续指针指向被删除结点的后续结点,则可完成删除。

我们设置两个指针,两个指针初始状态都指向哑结点,指针fast 先走n步,然后指针fast和指针slow同步往前继续遍历链表,直至fast的后续结点为空,此时指针slow到达被删除结点的前置结点


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

class Solution:
	def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
		if not head:
			return head
		slownode = ListNode(None)#创建一个初始值为none的空节点
		slownode.next = head
		fastnode = slownode
		for i in range(n):
			fastnode = fastnode.next
		while(fastnode.next!=None):
			slownode = slownode.next
			fastnode = fastnode.next
		if slownode.next == head:#如果要剔除的就是头节点
			head = head.next
		else:
			slownode.next = slownode.next.next
		return head

滑动窗口

3.无重复字符的最长字串,返回长度,看着esay,可惜有些测试用例没有通过

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # ans = ""#定义两个空字符串
        # temp = ""
        # for i in s:#不在里面的就添加,
        #     if i not in temp:
        #         temp += i
        #     else:#可能添加了会有冗余,这时开始收缩
        #         temp = temp[temp.index(i)+1:]  # 用到py的内置函数,字符串.index()会返回一个索引位置。
        #         #不止字符串,列表也用到index
        #         temp += i#在前面去掉之后在后面加上
        #         if len(temp)>len(ans): # 去比较窗口里面和最终结果的关系,进行替换
        #             ans = temp
        # return len(ans)
        #         if len(s)==0:
        #     return 0

567.字符串的排列

广度优先和深度优先

733.图像渲染

695.岛屿的最大面积

617.合并二叉树

116.填充每个节点的下一个

542.01矩阵

994.腐烂的橘子

递归/回溯

21.合并两个有序链表

206.反转链表

77.组合

784.字母大小写全排列

class Solution:
    def letterCasePermutation(self, S: str) -> List[str]:
        if not S:
            return ['']
        self.res=[]
        self.dfs(S,0,'')
        return self.res

    def dfs(self,S,i,temp):
        if i==len(S):
            self.res.append(temp)
            return 
        if S[i].isdigit():
            self.dfs(S,i+1,temp+S[i])
        else:
            self.dfs(S,i+1,temp+S[i].lower())
            self.dfs(S,i+1,temp+S[i].upper())

46.全排列

回溯法的三个基本要素:

    路径:已经做出的选择;
    选择列表:当前可以做出的选择;
    结束条件:结束一次回溯算法的条件,即遍历到决策树的叶节点

# 回溯算法,复杂度较高,因为回溯算法就是暴力穷举,遍历整颗决策树是不可避免的
结果 = []
def backtrack(路径, 选择列表):
    if 满足结束条件:
        结果.append(路径)
        return
    for 选择 in 选择列表:    # 核心代码段
        做出选择
        递归执行backtrack
        撤销选择


class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        # 回溯算法,复杂度较高,因为回溯算法就是暴力穷举,遍历整颗决策树是不可避免的
        res = []
        def backtrack(path=[], selects=nums):
            if not selects:
                res.append(path[:])
                return
            for i in range(len(selects)):
                path.append(selects[i])
                backtrack(path, selects[:i] + selects[i+1:])#在选择列表里除去 这次被选择的selected[i] ,然后递归
                path.pop()
        backtrack()
        return res

backtrack会被调用N!次,O(N!):这部分的复杂度是回溯算法不可避免的,最开始for循环N次,随递归的进行,每次递归循环减1次,N*(N-1)(N-2)...*1 = N!);
除了backtrack的调用,还包括列表的切片操作,O(N)
空间复杂度:O(N),取决于结果列表和递归栈深度。

动态规划

70.爬楼梯

198.打家劫舍

120.三角形最小路径和

位运算:

190.颠倒二位进制

136.只出现一次的数字

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值