LeetCode Python实现算法简介
边刷边记边总结,欢迎讨论与指导,持续更新
0001 两数之和
-
初始化一个字典 numtarget(哈希表、散列表),用来存储“若我需要 derta 凑成目标值,则应该寻找数组第 i 项”,即 numtarget[derta] = i
-
从前至后遍历数组,计算目标值 target 与当前整数 num 的差值 derta
-
查找 numtarget ,若已有 derta 记录则返回 i ,否则把 derta 与当前元素位置插入 numtarget
0002 两数相加
-
初始化一个链表 result ,只含有一个节点,赋值为零,用来存放计算和
-
对 l1 和 l2 从表头开始逐节点相加,有四种情况:
-
不产生进位,且 l1 或 l2 有后继节点,将无后继节点链表表尾补零节点,继续计算
-
不产生进位,且 l1 和 l2 均无后继节点,计算后结束
-
产生进位,且 l1 或 l2 有后继节点,将无后继节点链表表尾补零节点,继续计算,下一轮计算结果 +1
-
产生进位,且 l1 和 l2 均无后继节点,在result链表表尾补节点,取值为 1
-
0003 无重复字符的最长子串
-
初始化两个指针 a, b 指向第一个字符, 子串 substr, 表示指针 a, b 之间的子串,初始为空, 和最长子串长度 maxlen = 0
-
将指针 b 逐个后移
-
若 b 不在子串中,说明无重复字符,则将 b 加入 substr
-
若 b 在子串中,则找到 substr 中 "b" 的位置 i, 将 a 移动到 i+1 的位置,更新子串substr
-
-
指针 b 每后移一次,判断一次当前子串长度 len(substr) 与 maxlen 的大小关系
0004 寻找两个有序数组的中位数
暂略
0005 最长回文子串
可以暴力枚举,可以使用中心扩展算法,但使用 manacher 算法可使时间复杂降低至 O(n)
-
定义回文半径数组 radius,最右回文边界 r,最右回文边界的对称中心 c
-
遍历数组,有两种情况:
-
移动位置 i 在最大回文边界 r 的右边,那么以 i 为中心,向两边扩展,更新回文半径数组 radius[i],对称中心 c = i
-
移动位置 i 在最大回文边界 r 的左边或者在边界上,定义 i' 为与 i 关于 c 对称的点,il' 是以 i' 为中心的最长回文数组左边界, cl 是以 c 为中心的最长回文数组左边界。此时有三种情况:
-
i'l < cl,则位置 i 处的最长对称半径为 r - i + 1
-
i'l > cl,则位置 i 处的最长对称半径为 radius[i'l]
-
i'l = cl,则向最大回文边界 r 向右扩展,更新最大回文边界和对称中心
-
-
-
找到 radius 的最大值,推算子串
0006 Z字型变换
-
若指定行数小于等于 1,直接返回原字符串
-
将给定字符串 s 逐个写入, toword 指示方向,当行数为 0 或者 numRows - 1 时反向
-
按行拼接字符串
0011 盛最多水的容器
利用双指针
-
初始化两个指针,分别指向数组头尾,计算当前两个数字的盛水面积
-
调整数值较小的指针,当指针数字大于之前指针数字时,计算当前两个数字的盛水面积,比较记录更大值
-
按照 2 中规则遍历所有数字,得到最大值
0015 三数之和
两种解体思路
-
轮流做中,即遍历数组,然后简化为两数之和问题
-
双指针,将数组排序后,利用双指针遍历,剪枝
0016 最接近的三数之和
与0015题类似,将判断标准改变为三数之和与目标值的差值最小
0026 删除排序数组中的重复项
双指针法
-
初始化两个指针 i,j,起始位置都在数组头部
-
用 j 遍历数组,若 nums[j] = nums[i],跳过,若不相等,则令 nums[i] = nums[j]
0027 移除元素
双指针法
-
初始化两个指针 i = -1,j = 0
-
用 j 遍历数组,若等于指定值则跳过,否则将值赋给指针 i
0031 下一个排列
-
从后往前,找到第一个满足 nums[i] > nums[i-1] 的数字
-
在 nums[i:] 中,找到大于 nums[i-1] 的最小数字,交换两数,此时 nums[i:] 为降序排列
-
原地置逆 nums[i:],此时即找到下一个排列
-
若 1 中不存在满足条件的数字,将整个数组原地置逆
0033 搜索旋转排序数组
-
要求时间复杂度为O(logn),想到二分查找。取中间的元素 nums[m]
-
若 nums[m] < nums[r],则中间元素落在后半段。此时,若 nums[m] < target < nums[r],则 target 在 nums[m] 右侧,否则在左侧
-
若 nums[m] > nums[r],则中间元素落在前半段。此时,若 nums[l] < target < nums[m],则 target 在 nums[m] 左侧,否则在右侧
0034 在排序数组中查找元素的第一个和最后一个位置
-
第一个二分查找,找到数组中是否存在 target ,有返回位置 numposition ,无返回 [-1, -1]
-
在 numposition 左右分别二分查找,寻找开始位置和结束位置
0035 搜索插入位置
-
二分查找,若找到 target ,则返回位置,否则执行第二步
-
二分查找未果的最后一步时, 有 l = r = m,即左、右、中重合。因为数组是有序的,若 nums[m] > target, 则应在 m 处插入,否则在 m + 1 处插入
0039 组合总和
-
将数组按非递减排序
-
假设某元素 num 已在组合中,那么组合中其它元素和为 target-num,则原问题分解为 n 个小问题,n 表示数组长度
-
由于每个元素可重复使用,但组合不能重复,则根据排序后的数组,下一步迭代从元素自身位置开始,即忽略掉小于自身的元素,这部分元素若构成组合,应已经包含在本层迭代小于自身的元素组合中
0040 组合总和II
与0039类似,进一步剪枝,区别有两点:
-
每个元素不可重复,下一步迭代从下一个元素开始
-
数组中可能有相同元素,因此同层元素相同时,剪枝
0041 缺失的第一个正数
使用常数级别的空间,意味着需要在对数组本身进行操作
-
遍历数组,把 nums 中,数值为 i 的值放在 i-1 的位置。比如,若 num[i] 取值在 0~i 之间,那么将位置 i 处的元素 num[i] 与 位置在 num[i] 处的元素 nums[nums[i]]交换位置,直到位置 i 处的元素取值不在 0~i 之间
-
第二次遍历数组,若 nums[i] != i + 1,则缺失的第一个正数为 i + 1