挑战30天从入门到精通,每日打卡,长期有效,持续关注!!!以下除题目外,答案与解析均原创,转载请标明出处,感兴趣的同学欢迎评论区打卡~,
关注公众号【可与】,关注更多新鲜内容

【挑战30天掌握】算法与数据结构!!!

  • 算法与数据结构打卡【day1】
    • 3.19
      • 二分查找
        • 704. 二分查找
        • 278. 第一个错误的版本
        • 35. 搜索插入位置
      • 哈希表
        • 217. 存在重复元素
      • 动态规划
        • 53. 最大子数组和
  • 算法与数据结构打卡【day2】
    • 3.20
      • 双指针
        • 977. 有序数组的平方
        • 189. 轮转数组
        • 88. 合并两个有序数组
        • 反转字符串
      • 哈希表
        • 1. 两数之和
        • 字符串中的第一个唯一字符
  • 算法与数据结构打卡【day3】
    • 3.21
      • 双指针
        • 283. 移动零
        • 350. 两个数组的交集 II
      • 动态规划
        • 121. 买卖股票的最佳时机
      • 链表
        • 删除链表中的节点
  • 算法与数据结构打卡【day4】
    • 3.22
      • 双指针
        • 557. 反转字符串中的单词 III
      • 矩阵
        • 566. 重塑矩阵
      • 数学
        • 118. 杨辉三角
      • 链表 & 双指针
        • 删除链表的倒数第N个节点
  • 算法与数据结构打卡【day5】
    • 3.23
      • 链表
        • 876. 链表的中间结点
      • 滑动窗口
        • 3. 无重复字符的最长子串
      • 矩阵
        • 36. 有效的数独
        • 73. 矩阵置零
  • 算法与数据结构打卡【day6】
    • 3.24
      • 字符串/ 哈希映射 /哈希表
        • 387. 字符串中的第一个唯一字符
        • 383. 赎金信
        • 242. 有效的字母异位词
        • 567. 字符串的排列
  • 算法与数据结构打卡【day7】
    • 3.25
      • 链表
      • 深度优先/广度优先

算法与数据结构打卡【day1】

3.19

二分查找

704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/binary-search

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

278. 第一个错误的版本

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/first-bad-version

# The isBadVersion API is already defined for you.
# def isBadVersion(version: int) -> bool:class Solution:def firstBadVersion(self, n: int) -> int:left = 1right = n  # right总是指向错误版本# 确定相邻两个为False和True即可,由于若有一个true,他后都为true,# 让区间[left,right] = [false,true]从而将第一个true包含其中,缩紧边界,#让 left 为false或第一个true同时,让right为true,而后left==right时指向第一个truewhile left< right:mid = (left+right)//2if isBadVersion(mid):  # mid为trueright = mid    #让right为true  else:                # mid 为false, 此时mid+1可能为false或第一个trueleft = mid+1     # left 为false或第一个true# 此时 left==right 为第一个truereturn left

35. 搜索插入位置

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

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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/search-insert-position

class Solution:def searchInsert(self, nums: List[int], target: int) -> int:left = 0right = len(nums)-1if target> nums[right]:return len(nums)if target<nums[0]:return 0# 二分法总是将target包在[nums[left],nums[right]]之中,当发现nums里没有the exact "target",此时left与right颠倒,取left就可以while left<=right:mid = (left+right)//2if target==nums[mid]:return midelif target > nums[mid]:left = mid+1else :right = mid-1return left

哈希表

217. 存在重复元素

给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。
链接:https://leetcode.cn/problems/contains-duplicate/

  • 方法1
    利用python的集合
class Solution:def containsDuplicate(self, nums: List[int]) -> bool:if len(nums) == len(set(nums)):return Falseelse:return True
  • 方法2
    创建字典
class Solution:def containsDuplicate(self, nums: List[int]) -> bool:dic = {}for num in nums:if dic.get(num)==None:dic[num]=1else:dic[num]=dic[num]+1if dic[num] > 1:return Truereturn False

动态规划

53. 最大子数组和

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

示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/maximum-subarray

class Solution:def maxSubArray(self, nums: List[int]) -> int:# 以nums[i]结尾的最大和记为dp[i]# dp[i] = max(dp[i-1]+nums[i],nums[i])# 最大和为所有dp[i]中的最大值l = len(nums)dp = [min(nums)]*ldp[0]=nums[0]  #初始情况(边界)#只说输出最大连续子数组之和,并没有让输出数组本身for i in range(1,l):dp[i] = max(dp[i-1]+nums[i],nums[i])return max(dp)

算法与数据结构打卡【day2】

3.20

双指针

知识点讲解:

# 两个指针
# 1. 方向相反
#    求两数之和
#    e.g. 给定升序排列数组 nums=[1,2,3,4,12],求两数之和为7的下标,左指针left=0, 右指针right=4
#            nums[left]+nums[right]>7, right=right-1 ,
#            nums[left]+nums[right]<7, left = left +1 ,一直下去
def oppositeDirection(nums,target):left = 0right = len(nums)-1while left<right:if nums[left]+nums[right]==target:return left,rightelif nums[left]+nums[right]> target:right = right-1else:left = left +1return "Not found"
print(oppositeDirection([1,2,3,4,12],7))# 2. 方向相同
#    合并两个有序数组
#    [2,5,8,10],[1,2,4,6,11]
#    定义两个指针i,j分别指向两个数组元素,i,j从大到小比较数组,小的放在结果里,移动指针至两个指针指向末尾
#    code:
def sameDirection(lis1,lis2):l1 = len(lis1)l2 = len(lis2)i,j = 0,0l = []while i<=l1-1 and j<=l2-1:  #不满足两个条件,说明将l1或l2至少一个搬空if lis1[i]<=lis2[j]:l.append(lis1[i])i = i+1else:l.append(lis2[j])j = j+1if i<=l1-1:  #说明l1没有搬空l.extend(lis1[i:])if j<=l2-1:l.extend(lis2[j:])return l
# print(sameDirection([2,5,8,10],[1,2,4,6,11]))# 3. 一快一慢(快慢指针)
#    判断单链表是否存在“环”
#    设定指针p1,p2,其中p2的速度是p1的两倍,若存在环,p1会被再次追上#4. 指针同向,但起点不同
#   返回倒数第n个节点值
#   设定p2初始指向第n个节点,p1初始指向第1个节点,同时跑时,当p2指向最后一个节点时,p1指向倒数第n个节点

977. 有序数组的平方

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

示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array

  • 方法一,利用python内置方法
class Solution:def sortedSquares(self, nums: List[int]) -> List[int]:l = sorted([num**2 for num in nums])return l
  • 方法二:双指针
class Solution:def sortedSquares(self, nums: List[int]) -> List[int]:left = 0right = len(nums)-1l = []while left<=right:left_n,right_n = nums[left]**2,nums[right]**2# 此时左边和右边都为两侧最大值向中间递减,将最大值依次放入后倒转列表if left_n >= right_n:l.append(left_n)left = left+1else:l.append(right_n)right = right-1return list(reversed(l))

189. 轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
链接:https://leetcode.cn/problems/rotate-array

示例 1:输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]
  • 方法一:数组切片
class Solution:def rotate(self, nums: List[int], k: int) -> None:"""Do not return anything, modify nums in-place instead."""nums[:] = [*nums[-(k%len(nums)):],*nums[:-(k%len(nums))]]# 数组切片时间复杂度O(n),#等于其他语言中的新建一个数组,将原数组中的元素放到新数组中对应的位置上,然后再将新数组的元素复制到原数组中,时间复杂度为 O(n)# 注意这里不能直接nums = ,这样为指向了新的不属于in-place操作,# 这里 k 可能大于数组长度,当k等于len(nums)的倍数时,和原始数组相同
  • 方法二:反转数组
    反转三次数组得到
class Solution:def rotate(self, nums: List[int], k: int) -> None:"""Do not return anything, modify nums in-place instead."""# ---->-->k = k%len(nums)nums1 = nums[::-1]  # <--<----nums1_left =nums1[:k][::-1]  # -->nums1_right = nums1[k:][::-1] # ---->nums[:] = nums1_left+nums1_right # -->----># 注意这里不能直接nums = ,这样为指向了新的不属于in-place操作,# 这里 k 可能大于数组长度,当k等于len(nums)的倍数时,和原始数组相同# 注意这里如果用reversed,需要在用list(reversed),#          因为使用后类型为<list_reverseiterator object at 0x0000018F61C13880>

88. 合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:
输入: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 中的元素。

链接:https://leetcode.cn/problems/merge-sorted-array

方法1,使用额外数组复制

#使用双指针,注意深复制
#时间复杂度O(m+n)
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."""num_1 =nums1[:] #复制一份nums1用来排序,原来的nums1用来装结果,这里必须deepcopy,否则nums1变动,会影响num_1# 使用同向双指针,从小到大排i = 0j = 0k = 0while i<=m-1 and j<=n-1:  #两个数组都没有排完,若有一个数组排列完毕,index经过+1后会大于len-1if num_1[i]<=nums2[j]:nums1[k]=num_1[i]i = i+1k = k+1else:nums1[k]=nums2[j]j = j+1k = k+1if i<=m-1:while k<=m+n-1:nums1[k]=num_1[i]i = i+1k = k+1if j<=n-1:while k<=m+n-1:nums1[k]=nums2[j]j = j+1k = k+1

方法2,从大到小放入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."""#从后向前遍历数组i = m-1j = n-1k = m+n-1if m==0:nums1[:]=nums2while i>=0 and j>=0:  #任意一个排满了就退出if nums1[i]>=nums2[j]:nums1[k]=nums1[i]k = k-1i = i-1else:nums1[k]=nums2[j]k = k-1j = j-1# if i>=0:  #本身剩下的就不用移动了#     while k>=0:#         nums1[k]=num1[i]#         i = i-1#         k = k-1if j>=0:while k>=0:nums1[k]=nums2[j]j = j-1k = k-1

反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/xnhbqj/

class Solution:def reverseString(self, s: List[str]) -> None:"""Do not return anything, modify s in-place instead."""# 双指针# 对称交换for i in range(len(s)//2):s[i],s[-i-1]=s[-i-1],s[i]  # 这里其实相当于用temp额外空间O(1)进行交换

哈希表

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
链接:https://leetcode.cn/problems/two-sum

示例 1:输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:# 哈希映射mapDic = {}  #按顺序将mapDic 中存入nums的值和其index,{[num]:index}#从左往右计算每个num的互补值,如果mapDic中有其互补值,则已经找到,没有则将num及其index存入mapDic# 时间复杂度为O(n)for i in range(len(nums)):cur = target-nums[i]if mapDic.get(cur) !=None:  #mapDic中存在当前nums[i]的互补值return [mapDic[cur],i]else:mapDic[nums[i]]=i   #将nums[i]本身存入mapDic

字符串中的第一个唯一字符

给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。
示例 1:
输入: s = “leetcode”
输出: 0
链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/xn5z8r/

class Solution:def firstUniqChar(self, s: str) -> int:Dic = {}for i in range(len(s)):if Dic.get(s[i])==None:Dic[s[i]]=1else:Dic[s[i]]=Dic[s[i]]+1for i in range(len(s)):if Dic.get(s[i])==1:return ireturn -1

算法与数据结构打卡【day3】

3.21

双指针

283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

题目链接:https://leetcode.cn/problems/move-zeroes

方法1
遍历两遍
第一遍记录非零个数n
第二遍,i记录经过的非零个数-1,j向后移动,当nums[j]!=0时,放入nums[i],
最后将nums后的n个位置赋值0

class Solution:def moveZeroes(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""n = 0for i in range(len(nums)):if nums[i]==0:n = n+1i,j=0,0while j<len(nums)-1:if nums[i]!=0:i = i+1j = j+1else: #此时i指向第一个0while j<=len(nums)-2: #当j不是最后一个元素,继续向后移动j=j+1if nums[j]!=0:   #当当前位置不为零,将值放前面nums[i] = nums[j]i=i+1if n!=0:  #没有0,不需要剪切nums[-n:]=[0]*n

方法2
遍历一遍
指针i,记录第一个0的位置,j向后移动,当nums[j]!=0时,与nums[i]交换,
i++后j继续向后移动,直至j==len(nums)

class Solution:def moveZeroes(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""i,j=0,0while j<len(nums)-1: #j到达最后一个,停止操作if nums[i]!=0:i = i+1j = j+1else: #此时i指向第一个0while j<=len(nums)-2: #当j不是最后一个元素,继续向后移动j=j+1  if nums[j]!=0:   #当当前位置不为零,加入交换操作nums[i],nums[j]=nums[j],nums[i]i=i+1

方法3,python内置函数

class Solution:def moveZeroes(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""return nums.sort(key=lambda x:x==0)  #优先级高的放在最后

350. 两个数组的交集 II

给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]

链接:https://leetcode.cn/problems/intersection-of-two-arrays-ii

方法1,排序+双指针

class Solution:def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:nums1[:]=sorted(nums1)nums2[:]=sorted(nums2)ls = []i,j=0,0while i<=len(nums1)-1 and j<=len(nums2)-1: #若有一个测试完毕就退出if nums1[i]==nums2[j]: #当前元素相同ls.append(nums1[i])i=i+1j=j+1elif nums1[i]<nums2[j]:i=i+1else:j=j+1return ls

方法2,哈希表
创建一个哈希表H存储nums1元素出现次数,
在nums2中若H[num]存在,H[num]-1,且在结果中append这个num
默认len(nums1)<=len(nums2),否则在首行调用自身"func(nums2,nums1)"

# 官方版本
class Solution:def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:if len(nums1) > len(nums2):return self.intersect(nums2, nums1)m = collections.Counter()for num in nums1:m[num] += 1intersection = []for num in nums2:if m.get(num, 0) > 0:intersection.append(num)m[num] -= 1if m[num] == 0:m.pop(num)return intersection

动态规划

121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

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

原题链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock

class Solution:def maxProfit(self, prices: List[int]) -> int:if len(prices)==1:return 0earn = 0min_price = prices[0]for i in range(1,len(prices)):min_price = min(min_price,prices[i]) #寻找之前的最小的priceearn=max(prices[i]-min_price,earn)# dp[i]=max(dp[i−1],prices[i]−minprice)return earn

链表

删除链表中的节点

输入:head = [4,5,1,9], node = 1
输出:[4,5,9]
解释:指定链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9

提示:
链表中节点的数目范围是 [2, 1000]
-1000 <= Node.val <= 1000
链表中每个节点的值都是 唯一 的
需要删除的节点 node 是 链表中的节点 ,且 不是末尾节点
链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/xnarn7/

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = Noneclass Solution:def deleteNode(self, node):""":type node: ListNode:rtype: void Do not return anything, modify node in-place instead."""node.val = node.next.val  #将下一个节点的值赋给当前节点(当前结点的值已经被跳过)node.next = node.next.next #将下一节点的指针赋给当前节点的指针(当前节点的指针被跳过)

算法与数据结构打卡【day4】

3.22

双指针

557. 反转字符串中的单词 III

给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

示例 1:输入:s = "Let's take LeetCode contest"
输出:"s'teL ekat edoCteeL tsetnoc"

链接:https://leetcode.cn/problems/reverse-words-in-a-string-iii

方法1

class Solution:def reverseWords(self, s: str) -> str:i,j=0,0result = ""while j<len(s): #j出界时退出if s[i]==" ":i=i+1 #i,j跳过空格j=j+1result=result+" "else:  #i指向第一个非空元素while j<=len(s)-1 and s[j]!=" ": #跳出时j指向下一个空格或者j指向末尾j=j+1result=result+s[i:j][::-1]i=j   #此时一起指向空格return result

方法2 内置方法

class Solution:def reverseWords(self, s: str) -> str:ls = s.split(" ")ls[:] = list(map(lambda x:x[::-1],ls))return " ".join(ls)

矩阵

566. 重塑矩阵

在 MATLAB 中,有一个非常有用的函数 reshape ,它可以将一个 m x n 矩阵重塑为另一个大小不同(r x c)的新矩阵,但保留其原始数据。

给你一个由二维数组 mat 表示的 m x n 矩阵,以及两个正整数 r 和 c ,分别表示想要的重构的矩阵的行数和列数。

重构后的矩阵需要将原始矩阵的所有元素以相同的 行遍历顺序 填充。

如果具有给定参数的 reshape 操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。
链接:https://leetcode.cn/problems/reshape-the-matrix

方法1,元素赋值

class Solution:def matrixReshape(self, mat: List[List[int]], r: int, c: int) -> List[List[int]]:R = len(mat)C = len(mat[0])ls = []if r*c!=R*C:return matinner_ls =[0]*cfor i in range(r):for j in range(c):inner_ls[j] = mat[(j + i * c) // C][(j + i * c) % C]ls.append(inner_ls[:])  #这里需要用[:],否则当变量inner_ls改变时,原来赋值过的位置会一起改变return ls

方法二:切片赋值

class Solution:def matrixReshape(self, nums: List[List[int]], r: int, c: int) -> List[List[int]]:if len(nums)*len(nums[0])!=r*c:return numsl=[]new=[]for i in range(len(nums)):l+=nums[i]for i in range(0,len(l),c):new.append(l[i:i+c])return new

数学

118. 杨辉三角

给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。

示例 1:输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]

方法1,传统公式

class Solution:def generate(self, numRows: int) -> List[List[int]]:ls=[[1],[1,1]]inner_ls=[1,1]if numRows==1:return [[1]]if numRows==2:return lsfor i in range(2,numRows):cur=[1]for j in range(1,i):cur.append(inner_ls[j-1]+inner_ls[j])cur.append(1)inner_ls[:]=cur[:]  #储存生成的值,供下次使用ls.append(inner_ls[:])return ls

方法二:发现 错位之和为下一行答案:
如:
1 2 1 0
0 1 2 1

1 3 3 1
从而有:

class Solution:def generate(self, numRows: int) -> List[List[int]]:ls = [[1]]res = [1]while len(ls)<=numRows-1: ## 前面已经有一个初始情况,当numsRows==1时,直接返回lsres = [a+b for a,b in zip(res+[0],[0]+res)]ls.append(res)return ls

去掉一行

class Solution:def generate(self, numRows: int) -> List[List[int]]:ls = [[1]]while len(ls)<=numRows-1: ## 前面已经有一个初始情况,当numsRows==1时,直接返回lsres = [a+b for a,b in zip(ls[-1]+[0],[0]+ls[-1])]ls.append(res)return ls

链表 & 双指针

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

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
https://leetcode.cn/leetbook/read/top-interview-questions-easy/xn2925/

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:dummy = ListNode(next = head)  #实际上在head前面加了一个节点,从而防止head本身只有一个节点的删头问题,因为head的头部相当于dummy的中间(正数第一个节点)fast = dummyslow = dummyfor i in range(n): #与最后一个的间隔为n,此时slow指向的是倒数第n+1个fast = fast.nextwhile fast.next!=None:  #当fast没到尾部,退出时,fast为尾fast = fast.nextslow = slow.nextslow.next = slow.next.next #将倒数第n+1个节点的指针赋成倒数第n个节点的指针就可以了return dummy.next  #去掉在head处加的头部

算法与数据结构打卡【day5】

3.23

链表

876. 链表的中间结点

给你单链表的头结点 head ,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。

示例
输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

方法1,遍历两遍

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:n = 0p = headwhile p: #计算节点个数 , 注意head本身也算n=n+1p = p.nextmid_n = n//2Q = head  #已经算作第一个节点了for i in range(mid_n):  #加上前面的走的那一步,就是n//2+1Q = Q.nextreturn Q

方法2,使用数组

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:ls = [head]while ls[-1].next: #下一个节点不是None就放入,放入后下次检验的是刚刚放入的节点的下一节点ls.append(ls[-1].next)return(ls[len(ls)//2]) #注意这里实际上是len//2+1个,index为len//2

方法3,快慢指针,快指针是慢指针的2倍速

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:fast = headslow = headwhile fast and fast.next: #保证slow = slow.nextfast = fast.next.nextreturn slow

滑动窗口

3. 无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。示例 2:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

方法1,双指针,滑动窗口

class Solution:def lengthOfLongestSubstring(self, s: str) -> int:left,ans = 0,0while left<len(s):cur = 1 #初始化当前长度if left+1<len(s):               right = left+1s_set = {s[left]} #初始化当前集合(无需标号时,用集合比列表更快)while right<len(s) and s[right] not in s_set:s_set.add(s[right])cur = cur+1right = right+1ans = max(ans,cur)left = left +1return ans

方法2,使用哈希表、滑动变长区间
key为字符,value存储字符出现的最后一次位置,
保证[i,j]中没有重复字符串

class Solution:def lengthOfLongestSubstring(self, s):""":type s: str:rtype: int"""st = {}i, ans = 0, 0for j in range(len(s)):if s[j] in st:   i = max(st[s[j]]+1, i) #设为新的区间左端(舍弃经过的重复字符,保证区间左端到右端位置里没有重复字符窜)st[s[j]] = j    #记录当前字符串出现的位置indexans = max(ans, j - i+1)  #区间长度return ans

矩阵

36. 有效的数独

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

注意:

一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
空白格用 ‘.’ 表示。

输入:board =
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
输出:true
class Solution:def isValidSudoku(self, board: List[List[str]]) -> bool:""":type board: List[List[str]]:rtype: bool"""for i in range(3):s_set = {}for j in range(3):nums = [board[p][q] for p in range(i*3,i*3+3) for q in range(j*3,j*3+3) if board[p][q]!="."] if len(nums)!=len(set(nums)):return Falsefor i in range(9):nums_row = board[i]nums_row = list(filter(lambda x:x!=".",nums_row))if len(nums_row)!=len(set(nums_row)):return Falsenums_col = [board[j][i] for j in range(9) if board[j][i]!="."]if len(nums_col)!=len(set(nums_col)):return Falsereturn True

73. 矩阵置零

方法1,时间复杂度O(mn),空间复杂度O(mn)

class Solution:def setZeroes(self, matrix: List[List[int]]) -> None:"""Do not return anything, modify matrix in-place instead."""m = len(matrix)n = len(matrix[0])set_0 = []for i in range(m):for j in range(n):if matrix[i][j]==0:set_0.append((i,j))for i,j in set_0:matrix[i] = [0]*nfor k in range(m):matrix[k][j]=0

方法2,时间复杂度O(mn),空间复杂度O(m+n)
因为行列都要清零,所以直接储存要清零的行和列就行

class Solution:def setZeroes(self, matrix: List[List[int]]) -> None:"""Do not return anything, modify matrix in-place instead."""m = len(matrix)n = len(matrix[0])rows=set()cols=set()for i in range(m):for j in range(n):if matrix[i][j]==0:rows.add(i)cols.add(j)for row in rows:matrix[row] = [0]*nfor col in cols:for k in range(m):matrix[k][col]=0

方法3,时间复杂度O(mn),空间复杂度O(1)
利用矩阵第一行和第一列存储行列是否为零的信息
利用额外的两个标量存储第一行和第一列的信息

class Solution:def setZeroes(self, matrix: List[List[int]]) -> None:"""Do not return anything, modify matrix in-place instead."""m = len(matrix)n = len(matrix[0])find_row = any( matrix[0][j]==0 for j in range(n))find_col = any( matrix[i][0]==0 for i in range(m))for i in range(1,m):   #注意要从index==1开始for j in range(1,n):if matrix[i][j]==0:matrix[i][0] = matrix[0][j] = 0 #如果当前元素为零,则这一行和列都为零,在第一行和第一列做标记for i in range(1,m):for j in range(1,n):if matrix[i][0]==0 or matrix[0][j]==0: #根据标记置零matrix[i][j]=0if find_row :matrix[0] = [0]*nif find_col:for k in range(m):matrix[k][0]=0

算法与数据结构打卡【day6】

3.24

字符串/ 哈希映射 /哈希表

387. 字符串中的第一个唯一字符

给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。

方法1,哈希映射,二次遍历

class Solution:def firstUniqChar(self, s: str) -> int:dic = {}for i in range(len(s)):if dic.get(s[i] )==None:dic[s[i]]=i   #存储indexelse:dic[s[i]]=-1ans = len(s)flag = Falsefor k,v in dic.items():if v!=-1:flag = Trueans = min(ans,v)if flag:return anselse:return -1

方法2,字母表
唯一出现的元素左起index和右起index相同

class Solution:def firstUniqChar(self, s: str) -> int:min_index = len(s)for i in 'abcdefghijklmnopqrxtuvwxyz':left = s.find(i)if(i in s and s.rfind(i)==left):min_index = min(min_index, left)return min_index if(min_index<len(s)) else -1

383. 赎金信

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/ransom-note

方法1,字符统计
哈希表,二次遍历
第一遍记录表值,第二遍减去表中值

class Solution:def canConstruct(self, ransomNote: str, magazine: str) -> bool:m_has={}for m in magazine:if m_has.get(m)==None:m_has[m]=1else:m_has[m]=m_has[m]+1for r in ransomNote:if m_has.get(r)==None or m_has[r]==0:return Falseelse:m_has[r]=m_has[r]-1return True

简化以上代码

class Solution:def canConstruct(self, ransomNote: str, magazine: str) -> bool:if len(ransomNote)>len(magazine):return Falseelse:return not collections.Counter(ransomNote)-collections.Counter(magazine) #返回字典差集,如果有元素,说明ransomNote里面有magazine中没有的元素,所以not true == false,  反之没有元素说明magazine包含ransomNote, not 空 == true#注意 not {}或not () 或 not 1 都是true

这里Counter是collections里的一个计数器,是字典的子类
用法:

import  collections
print(collections.Counter("abcdsbb"))
print(collections.Counter("abcdsbb")-collections.Counter("abcds"))
print(collections.Counter("abcds")-collections.Counter("abcds"))

输出:

Counter({'b': 3, 'a': 1, 'c': 1, 'd': 1, 's': 1})
Counter({'b': 2})
Counter()

242. 有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

class Solution:def isAnagram(self, s: str, t: str) -> bool:return collections.Counter(s)==collections.Counter(t)

567. 字符串的排列

给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。
换句话说,s1 的排列之一是 s2 的 子串 。

示例 1:
输入:s1 = "ab" s2 = "eidbaooo"
输出:true
解释:s2 包含 s1 的排列之一 ("ba").

方法1,哈希映射(字典)

class Solution:def checkInclusion(self, s1: str, s2: str) -> bool:if len(s1)>len(s2):return Falsecount_s1 = collections.Counter(s1)n = len(s1)for i in range(len(s2)):if count_s1.get(s2[i])!=None:if count_s1 == collections.Counter(s2[i:(i+n)]):return Truereturn False

优化以上算法

class Solution:def checkInclusion(self, s1: str, s2: str) -> bool:if len(s1)>len(s2):return Falsecount_s1 = collections.Counter(s1)n = len(s1)count_s2 = collections.Counter(s2[:n])if count_s1 == count_s2:return Truefor i in range(n,len(s2)): #以长度为n的窗口滑动, i代表区间右端点count_s2[s2[i-n]] = count_s2[s2[i-n]]-1if count_s2.get(s2[i])==None:count_s2[s2[i]] = 1else:count_s2[s2[i]] = count_s2[s2[i]]+1if count_s1 == count_s2: return Truereturn False

方法2,哈希表
26个字母,index表示第几个字母,value表示个数
原理同上

class Solution:def checkInclusion(self, s1: str, s2: str) -> bool:n, m = len(s1), len(s2)a = ord("a") # 97if n > m:return FalsecharCount1 = [0]*26charCount2 = [0]*26for i in range(n):charCount1[ord(s1[i])-a] += 1charCount2[ord(s2[i])-a] += 1if charCount1 == charCount2:return Truefor j in range(n,m):charCount2[ord(s2[j])-a] += 1charCount2[ord(s2[j-n])-a] -= 1if charCount1 == charCount2:return Truereturn False

算法与数据结构打卡【day7】

3.25

链表

深度优先/广度优先

【挑战30天掌握】算法与数据结构!!!相关推荐

  1. 挑战程序设计竞赛2:算法和数据结构 (渡部有隆 著)

    1 转载于:https://www.cnblogs.com/revoid/p/9596083.html

  2. 挑战程序设计竞赛(算法和数据结构)——14.1互质的集合(并查集)的JAVA实现

    题目与思路: 代码: import java.util.Scanner; import java.util.Vector;public class DisjointSet {public static ...

  3. 挑战程序设计竞赛(算法和数据结构)——19.2九宫格拼图问题的JAVA实现

    题目&解题思路: 代码: import java.io.PushbackInputStream; import java.util.*;public class Puzzle_9 {publi ...

  4. 「算法与数据结构」时间与空间复杂度

    写在前面 可能有些人会吐槽,学算法有什么用,顶多就是去面试大厂的时候能用上,大厂面试算法也只是强中筛强的一个敲门砖而已,我又不去面大厂,不用学它,真的是这样吗? 肯定不是,在计算机行业发展,不管是前端 ...

  5. 【操作指导 | 代码实现】挑战程序设计竞赛2:算法和数据结构

    书籍封面 第一章 前言 1. 本人衷心建议 ~~~~~~       如果你是一位初学者,我指的是你只会基本的 C/C++ 编程,即使编的很烂,这本书对于你算法和数据结构的提升非常有帮助,所涉及的每一 ...

  6. 一看“左程云:200道算法与数据结构”,二刷“阿里云:70+算法题、30种大厂笔试高频知识点”,3月过去终于挺进我梦中的字节!

    不管是学生还是已经工作的人,我想彼此都有一个相同的梦想:进大厂! 眼看着2020年还有个三十来天就要完美收尾了,那么如何才能在未来三个月弯道超车赶上"金三银四的春招",进入梦寐以求 ...

  7. noj数据结构稀疏矩阵的加法十字链表_一个算法毁了一款好游戏?算法和数据结构到底有多重要?...

    来源 | 异步 | 文末赠书 前段时间大火的国产游戏--<太吾绘卷>,由于创新的玩法和精良的制作一度广受好评,然而随着玩家游戏的深入和时长的积累,发现该游戏在玩的过程中游戏外的问题很多很多 ...

  8. 算法与数据结构简单启蒙,我当年学习算法走过的坑

    1.碎碎念 我的算法启蒙来自于紫书算法竞赛入门经典,但是不得不说从语言过度到算法,紫书并不是一个很好的开始.当时整本书除了数学和图论其实是看完了的,但真的有印象的大约只有暴力枚举法中枚举排列,子集生成 ...

  9. 算法与数据结构+一点点ACM从入门到进阶吐血整理推荐书单

    前言:技术书阅读方法论 一.速读一遍(最好在1~2天内完成) 人的大脑记忆力有限,在一天内快速看完一本书会在大脑里留下深刻印象,对于之后复习以及总结都会有特别好的作用. 对于每一章的知识,先阅读标题, ...

最新文章

  1. iphone通讯录批量删除_iPhone通讯录删除了如何恢复?用对方法快速找回,亲测有效!_...
  2. 信号建模与参数估计作业重新计算
  3. Linux 中执行命令
  4. 第12天学习Java的笔记(数组小练习,数组与方法)
  5. Tampermonkey油猴插件各种浏览器下载教程【chrome、firefox、Edge、360、QQ、Safari等】
  6. android java 延时函数,如何在Android中设置文本之间的延迟
  7. java.lang.IllegalStateException: attempt to re-open an already-closed object
  8. 字符串中全角半角之间的转换
  9. 2017c语言考核册答案,2017年电大《C语言程序设计》形成性考核册答案.doc
  10. 港大南科大提出端到端PDVC,用DETR的方法做Dense Video Captioning!简化训练流程
  11. 1001.A+B Format (20) 解题
  12. 基金:能赚大钱的人往往会在3个方面谨慎
  13. azure备份存储层分类_备份到Azure –如何做到这一点?
  14. spark 运行自带python示例的方式
  15. VB在菜单上增加图标
  16. 【HNOI2006】【BZOJ1192】鬼谷子的钱袋(水题,位运算?)
  17. 配置WindowsLiveWriter,写cnblogs博客
  18. 计算机策略组无法打开怎么办,本地组策略打不开,怎么解决
  19. 计算机折线图教程,excel怎么插入折线图 excel怎么将多个折线图合并
  20. 冷山的博客思听书摘索引页

热门文章

  1. PyQt4的学习历程(3)
  2. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version
  3. 【Angular】Angular开发组件
  4. php源文件怎么打开,php文件怎么打开?
  5. SpringCloud-Alibaba之Nacos服务注册和发现
  6. java jsp eq_javaWeb核心技术第九篇之JSP
  7. 每日一句api Android,金山每日一句 API 接口调用接入方法
  8. vm虚拟机安装教程及注意事项
  9. Tiny OS+nblot,值得程序员体验吗?
  10. MySQL连接查询练习