Leetcode学习笔记 数组和字符串

数组和字符串-22

数组简介-3

寻找数组的中心索引,简单
搜索插入位置,简单

合并区间,中等
对区间列表根据左端点排序:

intervals.sort(key=lambda x: x[0])
intervals = sorted(intervals, key=lambda x:x[0])

对二维列表 lst 根据第 i 列进行排序:

lst.sort(key=lambda x: x[i])
lst = sorted(lst,key=lambda x:x[0])

注意:

  • lst.sort() 是在原列表上进行排序,不需要返回
  • sorted(lst)是返回排序后的列表,需要重新赋值

二维数组简介-3

旋转矩阵,中等
两种方法:

方法一:将原矩阵四等分为四块,每块小矩阵均顺时针旋转90°并移动到下一块的位置。
将原地旋转的问题转化为四个小块分别移动且旋转的问题,只要有移动,就只需要常数个额外空间
注:Python中写交换不用引入临时变量
直接a , b = b , aa , b , c , d = b , c , d , a即可

方法二:翻转法
顺时针旋转90° = 水平翻转一次 + 沿主对角线翻转一次 = 竖直翻转一次 + 沿副对角线翻转一次
可以直接将奇偶数情况合成一段代码

零矩阵,中等

对角线遍历,中等
遍历第一行和最后一列,作为每一次对角线遍历的起点
每次对角线遍历存入一个临时列表,根据对角线条数的奇偶性决定临时列表是否翻转
将翻转(不一定)处理过的列表extend到答案列表 lst 里,最后返回 lst

字符串简介-4

最长公共前缀,简单
逐位比较,有不同的直接返回
在字符串末尾增加某个字符用str = str + char

用列表作为输入的题都要先判断列表是否为空再继续写
Python中判断列表为空的语句:if not lst: return xxx空列表的 bool 值为 False,非空列表为 True

取字符串子串的方法:str[a:b] a 表示起点,可以空着,b表示终点之后,也可以空着

最长回文子串,中等
Python 给列表赋初值:resubstr = [[False for i in range(n)] for j in range(n)]

方法一:动归
初始值:单字符是回文串,两个相同字符是回文串
循环遍历:根据 子串长度从小到大遍历
最后的答案要返回一个最长回文子串,需要从0开始比较每次True的回文串是不是比答案长,不要遗漏一个字符和两个字符的情况

方法二:中心扩展
从方法一的边界条件,也就是单字符和双字符的情况开始,双向扩展,知道两边的新字符不同或到达字符串头尾停止

翻转字符串里的单词,中等

去除字符串收尾空格 [ 其他字符 ]:str.strip(['其他字符'])
将字符串按空格 [ 其他字符 ] 划分存入列表:lst = str.split([其他字符])
官解用了join方法,就一行:
join方法的语法: "单词间的间隔".join(被连接的字符(串)列表对象) ,有返回值
reversed方法:reversed(需要翻转的迭代器),有返回值

class Solution:
    def reverseWords(self, s: str) -> str:
        return " ".join(reversed(s.split()))

进阶:尝试使用 O(1) 额外空间复杂度的原地解法。
不会

实现 strStr(),简单
用Python的 str.find(substr)可以直接秒杀
自己写:
暴力逐一比较,外层循环只需要执行 len1 - len2 + 1 次,复杂度O(mn)
需要考虑要查找的子串比主串更长的情况

双指针技巧-6

双向双指针
翻转字符串,简单
从两头开始依次交换

数组拆分I,简单
排序取奇数位置的数求和

两数之和 II - 输入有序数组,简单
暴力时间复杂度O(n²)
方法一:二分查找,时间复杂度O(nlongn)

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        n = len(numbers)
        for i in range(n):
            low, high = i + 1, n - 1
            while low <= high:
                mid = (low + high) // 2
                if numbers[mid] == target - numbers[i]:
                    return [i + 1, mid + 1]
                elif numbers[mid] > target - numbers[i]:
                    high = mid - 1
                else:
                    low = mid + 1

方法二:双指针,时间复杂度O(n)
题目假设唯一解,则在数组有序的情况下,假设解为 ( x , y ) ,i , j 从两边开始遍历时,假如解 ( i , j ) 的值比 target 小了,则一定有 i < x ,应该继续加大 i ,如果加大 j ,则退回了之前遍历过的情况,一定不会得到 target 。同理假如 ( i , j ) 的值比 target 大了,则应该继续减小 j 。
结合:二分查找结合双指针,时间复杂度最好O(logn),最坏O(n)

单向双指针
移除元素,简单
根据题目描述直接对列表进行修改

最大连续1的个数,简单

长度最小的子数组,中等
这道题如果每次重新对子列表求和的话,复杂度至少为O(nlogn)
使用双指针维护一个唯一的字列表和,前指针增加新元素,后指针减少子列表头元素,复杂度降低为O(n)

小结部分-6
杨辉三角,简单
双层循环,处理好边界,复杂度O(N²)

杨辉三角 II,简单
单求第k层的各个元素,空间复杂度优化至 O(k) 的方法:
维护一个临时数组,杨辉三角的每一层等于两个错一位的上一层相加
比如 [ 1,3,3,1 ] ==> [ 0,1,3,3,1 ] + [ 1,3,3,1,0 ] = [ 1,4,6,4,1 ]

反转字符串中的单词 III,简单

  1. 字符串没有 reverse() 方法,使用 reversed(str) 对字符串进行处理后得到的是反转后的字符列表
  2. res = s[::-1] 可以得到反转的字符串

寻找旋转排序数组中的最小值,中等

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

直接根据右边端点和中点的大小关系讨论,可以减少为两种情况:

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

删除排序数组中的重复项,简单
简单的同向双指针,跟双指针那道“去除元素”做法一样

移动零,简单
用双指针
一开始的思路是每次给左边的指针赋值右边的非零值,右边指针遍历一遍后,左边指针再继续遍历数组,将剩余位置的零补全。这样最优情况需要遍历一遍,最差情况需要遍历两遍。
优化为:每次检测到非零数,左右两指针的值交换。这样无论最优还是最差都只需遍历一遍

你可能感兴趣的:(LeetCode学习笔记)