leetcode刷题笔记--第1-10题

1.两数之和

题目

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

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

解法1 时间复杂度o(n²) 空间复杂度o(1)

外层遍历数组, 内层从外层遍历到的数组的下一个数开始遍历到尾部,找到相加和为target的两个数

解法2 时间复杂度o(n) 空间复杂度o(n)

先遍历一遍, 将值和位置保存在哈希数组里面(key是值 value是位置)

再遍历一遍, 寻找target - 当前遍历到数字的值 在哈希数组里面存在 并且不是自己 返回(这题数组内的值不会重复)

2. 两数相加

题目

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

解法 时间复杂度o(n+m)

因为是逆序的 直接最简单从两个列表头结点遍历相加即可,使用一个变量保存进位信息

最后再遍历比较长的那个连表把剩下的值加上去即可(使用一个指针变量指向还不为空的链表指针而不是对两个指针做while操作 因为走到这一步一定最多只有一个链表没有遍历完)

3.无重复字符字符串

题目

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

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

解法 时间复杂度o(n) 空间复杂度o(n)

利用一个哈希数组记录所有字符串出现信息, key是字符, value是字符出现的最后位置

遍历这个字符串,每次都更新字符串的出现位置,同时一个变量记录当前计算子串的开始计算位置

如果当前字符出现过(在哈希数组里存在且出现位置大于等于这一轮子串开始位置),判断更新子串最大长度即可,新的字符子串位置则为当前字符上一次出现字符的位置+1

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

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。时间复杂度为log(m+n)

nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0

解法 时间复杂度log(m+n) 空间复杂度o(1)

分析

这题比较麻烦 最终状态 假定有这么一条线将这两个数组分割为两半

A[0] A[1] A[2] ... A[i-1] | A[i] A[i+1] ... A[n]
B[0] B[1] B[2] ... B[j-1] | B[j] B[j+1] ... B[m]

左边数组元素个数: i + j 右边数组元素: m + n - i - j

此时 需要满足

|右边元素个数 - 左边元素个数| <= 1

A[i] > B[j-1]

B[j] > A[i-1]

中位数 = (max(A[i-1], B[j-1]) + min(A[i], B[j])) /2 或者 max(A[i-1], B[j-1]) 或者 min(A[j], B[j]) 根据左右元素个数而定

但是边界条件挺多的 分割线在第一个元素左边 或 最后一个元素的右边,可以使得 len(A) >= len(B)减少一点边界条件的组合

计算过程

  • 两个数组开始时都是从中间开始切 然后调整线的位置,调整的时候就是用二分法调整,优先满足

    A[i] > B[j-1]

    B[j] > A[i-1]

    根据左右元素的个数和A[i] B[j-1] B[j] A[i-1]大小关系调整

  • 保证以上关系再调整,满足

    |右边元素个数 - 左边元素个数| <= 1

    同样也是根据左右元素的个数和A[i] B[j-1] B[j] A[i-1]大小关系调整

  • 获取中位数

其实比较麻烦的计算中位数时边界条件不少

5.最长回文子串

题目

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

解法 时间复杂度 o(n²) 空间复杂度o(1)

假定回文的中线要么在某字符上 要么在两个字符中间 如

中线0  中线1 中线2 中线3 中线4 中线5 中线6 中线7
  b                  a                  b               a           d

遍历中线位置 往两边拓展即可 值得注意的是要注意中线是在字符上面的时候 长度从1往上涨

6.Z形变换

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:

L   C   I   R
E T O E S I I G
E   D   H   N

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"

解法一 时间复杂度 o(n) 空间复杂度o(n²)

计算出行数 然后将数据按形状填入一个二维数组 最后在横向输出

解法二 时间复杂度o(n) 空间复杂度o(1)

可以找到每一行输出时的规律:

假定每一行行号从0开始,

  • 每行第一个字符在原字符串的位置一定是0, 1, 2, 3 ... 行数 - 1

  • 第一行和最后一行 每两个字符间隔是(行数 - 1) * 2

  • 中间的行每两个字符间隔是 (行数-1) * 2 - 当前行号2 当前行号 2 交替

遍历行数即可 (当计算的坐标大于字符串长度时跳到下一行)

7.整数反转

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

输入: 123
输出: 321

假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

解法 时间复杂度o(n) 空间复杂度o(1)

如果是负数 取反先算

使用一个变量 一边取出个位数一边计算

var ret int
for x > 0 {
  ret = ret * 10 + x % 10
  x /= 10
  // 溢出检查
}

感觉在循环里面做溢出检查好一些 不过比较坑的是溢出返回的是0 所以负数和正数计算上下限不一样

8.字符串转整数

9.回文数字 时间复杂度o(n) 空间复杂度o(1)

题目

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

输入: 121
输出: true
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

解法

先直接判断输入 为0返回true 小于0或者是%10 == 0 返回false节约一些case的时间

算的时候类似 整数反转, 算出整数反转的数是否等于原来的数即可

10.正则表达式匹配

题目

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.''*' 的正则表达式匹配。

'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
输入:
s = "aa"
p = "a*"
输出: true
解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。

解法 时间复杂度o(n²) 空间复杂度o(1)

正常遍历s 和 p即可 注意当s或者p遍历之后结果的判断

如果碰到 .* 或者 字符* 并且符合匹配到当前字符的时候需要走两个分支, 一个将这个字符算在匹配到 (a*) 这个表达式里,一个是不算, 类似于

func match(s, p string, sPtr, pPtr int)
if p[pPtr+1] == '*' {
  if p[pPtr] == '.' || s[sPtr] == p[pPtr] {
    return match(s, p, sPtr + 1, pPtr) || match(s, p, sPtr, pPtr)
  }
}

猜你喜欢

转载自www.cnblogs.com/Me1onRind/p/11832269.html