LeetBook 列表/数组和字符串

LeetBook系列博客记录一下Leetcode中书籍的一些题目解法。题目均来自https://leetcode-cn.com/。
  
  

724. 寻找数组的中心下标

难度:简单
  
给你一个整数数组 nums,请编写一个能够返回数组 “中心下标” 的方法。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果数组不存在中心下标,返回 -1 。如果数组有多个中心下标,应该返回最靠近左边的那一个。
注意:中心下标可能出现在数组的两端。

示例 1

输入:nums = [1, 7, 3, 6, 5, 6]
输出:3
解释:
中心下标是 3 。
左侧数之和 (1 + 7 + 3 = 11),
右侧数之和 (5 + 6 = 11) ,二者相等。

示例 2

输入:nums = [1, 2, 3]
输出:-1
解释:
数组中不存在满足此条件的中心下标。

示例 3

输入:nums = [2, 1, -1]
输出:0
解释:
中心下标是 0 。
下标 0 左侧不存在元素,视作和为 0 ;
右侧数之和为 1 + (-1) = 0 ,二者相等。

提示
nums 的长度范围为 [0, 10000]。
任何一个 nums[i] 将会是一个范围在 [-1000, 1000]的整数。

比较容易想到暴力解法:循环列表,每次计算索引左右两边的和

class Solution:
    def pivotIndex(self, nums: List[int]) -> int:
        for i in range(len(nums)):
            if sum(nums[:i]) == sum(nums[i + 1:]):
                return i
        return -1

优化一下,遍历的时候不使用sum求和,用left记录索引左边的和,用left*2+nums[i]和原列表之和比较。

class Solution:
    def pivotIndex(self, nums: List[int]) -> int:
        sum_ = sum(nums)
        left = 0
        for i in range(len(nums)):
            if left * 2 + nums[i] == sum_:
                return i
            else:
                left += nums[i]
        return -1

  
  

35. 搜索插入位置

难度:简单
  
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。

示例 1:

输入: [1,3,5,6], 5
输出: 2

示例 2:

输入: [1,3,5,6], 2
输出: 1

示例 3:

输入: [1,3,5,6], 7
输出: 4

示例 4:

输入: [1,3,5,6], 0
输出: 0

暴力解法:遍历一遍,注意索引位置

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        for i in range(len(nums)):
            if target <= nums[i]:
                return i
        return len(nums)

优化:二分法

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        l, r = 0, len(nums)
        while l < r:
            m = (l + r) // 2
            if target < nums[m]:
                r = m
            elif target > nums[m]:
                l = m + 1
            else:
                return m
        return l

  
  

56. 合并区间

难度:中等
  
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

提示:

1 <= intervals.length <= 10000
intervals[i].length == 2
0 <= starti <= endi <= 104

先将原列表排好序了,添加一个到res中,然后遍历比较每个列表中区间的开头和res中最后一个区间的结尾,这里直接修改了res最后一个区间的结尾。

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort()
        if len(intervals) == 0:
            return
        res = [intervals[0]]
        for i in range(1, len(intervals)):
            if res[-1][1] >= intervals[i][0]:
                res[-1][1] = max(res[-1][1], intervals[i][1])
            else:
                res.append(intervals[i])
        return res

  
  

面试题 01.07. 旋转矩阵(同题48)

难度:中等
  
给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。
不占用额外内存空间能否做到?

示例 1:
给定

matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],

原地旋转输入矩阵,使其变为:

[
[7,4,1],
[8,5,2],
[9,6,3]
]

示例 2:

给定 matrix =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
],

原地旋转输入矩阵,使其变为:

[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]

有很多神奇的解法,个人觉得最好理解的就是先对角线翻转,然后水平翻转。

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        N = len(matrix)
        for i in range(N):
            for j in range(i):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
        for i in range(N):
            matrix[i][:] = matrix[i][::-1]

  
  

73. 矩阵置零

难度:中等
  
编写一种算法,若M × N矩阵中某个元素为0,则将其所在的行与列清零。
示例 1
输入:

[
[1,1,1],
[1,0,1],
[1,1,1]
]

输出:

[
[1,0,1],
[0,0,0],
[1,0,1]
]

示例 2
输入:

[
[0,1,2,0],
[3,4,5,2],
[1,3,1,5]
]

输出:

[
[0,0,0,0],
[0,4,5,0],
[0,3,1,0]
]

暴力法,记录下所有的0出现的位置,然后再遍历

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

比较通俗一点的暴力解法,用两个set去分别存0出现的位置


class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        """
        :type matrix: List[List[int]]
        :rtype: void Do not return anything, modify matrix in-place instead.
        """
        R = len(matrix)
        C = len(matrix[0])
        rows, cols = set(), set()

        # Essentially, we mark the rows and columns that are to be made zero
        for i in range(R):
            for j in range(C):
                if matrix[i][j] == 0:
                    rows.add(i)
                    cols.add(j)

        # Iterate over the array once again and using the rows and cols sets, update the elements
        for i in range(R):
            for j in range(C):
                if i in rows or j in cols:
                    matrix[i][j] = 0

优化解法

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        """
        :type matrix: List[List[int]]
        :rtype: void Do not return anything, modify matrix in-place instead.
        """
        row = len(matrix)
        col = len(matrix[0])
        row0_flag = False
        col0_flag = False
        # 找第一行是否有0
        for j in range(col):
            if matrix[0][j] == 0:
                row0_flag = True
                break
        # 第一列是否有0
        for i in range(row):
            if matrix[i][0] == 0:
                col0_flag = True
                break

        # 把第一行或者第一列作为 标志位
        for i in range(1, row):
            for j in range(1, col):
                if matrix[i][j] == 0:
                    matrix[i][0] = matrix[0][j] = 0
        #print(matrix)
        # 置0
        for i in range(1, row):
            for j in range(1, col):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0

        if row0_flag:
            for j in range(col):
                matrix[0][j] = 0
        if col0_flag:
            for i in range(row):
                matrix[i][0] = 0

  
  

498. 对角线遍历

难度:中等
  
给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。

示例:

输入:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
输出: [1,2,4,7,5,3,6,8,9]
解释:
在这里插入图片描述

说明:

给定矩阵中的元素总数不会超过 100000 。

主要根据观察模拟过程:
由观察可以得知,一共有两种走法,向右上方走和向左下方走。
再由二维数组的特性可以得知,向右上方走实际上等于 x -= 1, y += 1, 向左下方走实际上等于 x+= 1, y -= 1
1.当向右上方走的时候,有两种情况会造成碰壁,因而需要转弯,
CASE 1: 碰到上方的壁 (x无法再 - 1),但还没碰到右方的壁(y可以 +1)
在这种情况下,下一步的坐标为 y += 1, 比如图里的 1 --> 2
CASE 2: 碰到右方的壁 (y无法再 +1)
在这种情况下, 下一步的坐标为 x += 1, 比如图里的 3 --> 6
2.向左下方走同理:
CASE 1: 碰到左方的壁 (y无法再 -1), 但还没有碰到下方的壁(x可以 +1)
在这种情况下,下一步的坐标为 x += 1, 比如图里的 4 --> 7
CASE 2: 碰到下方的壁 (x无法再 +1)
在这种情况下,下一步的坐标为 y += 1, 比如图里的 8 --> 9

class Solution:
    def findDiagonalOrder(self, mat):
        if not mat or not mat[0]:
            return []
        M, N = len(mat), len(mat[0])
        x, y = 0, 0
        matrix_num = M * N
        count = 0
        direction = 'up'
        res = []
        while count < matrix_num:
            count += 1
            res.append(mat[x][y])
            # 先往右上走
            if direction == 'up':
                # 不需要调整方向的条件
                if x > 0 and y < N - 1:
                    x -= 1
                    y += 1
                else:
                    direction = 'down'
                    # 1 到 2 这种
                    if x == 0 and y < N -1:
                        y += 1
                    # 3 到 6 这种
                    elif y == N -1:
                        x += 1
            else:
                # 不需要调整方向的条件
                if x < M -1 and y > 0:
                    x += 1
                    y -= 1
                else:
                    direction = 'up'
                    # 4 到 7 这种
                    if x < M -1 and y == 0:
                        x += 1
                     # 8 到 9 这种
                    elif x == M -1:
                        y += 1
        return res


A = Solution()
print(A.findDiagonalOrder([
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]))

还可以先根据横坐标与纵坐标之和是一个定值,在一条对角线上。
然后遍历这些数组,数组的反向,正向,反向…输出这些数字。

class Solution:
    def findDiagonalOrder(self, matrix: List[List[int]]) -> List[int]:
        group = collections.defaultdict(list)
        for r,row in enumerate(matrix):
            for c,num in enumerate(row):
                sums = r + c
                group[sums].append(num)
        res = []
        for k,s in enumerate(group.values()):
            if k % 2 == 0:
                s = s[::-1]
            for p in s:
                res.append(p)
        return res

  
  

14. 最长公共前缀

难度:简单
  

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “”。

示例 1:

输入:strs = [“flower”,“flow”,“flight”]
输出:“fl”

示例 2:

输入:strs = [“dog”,“racecar”,“car”]
输出:""
解释:输入不存在公共前缀。

提示:

0 <= strs.length <= 200
0 <= strs[i].length <= 200
strs[i] 仅由小写英文字母组成

通过min和max就把字符串的相同项归类了,再输出不同值之前的相同项

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if not str:
            return
        s1 = min(strs)
        s2 = max(strs)
        for i in range(len(s1)):
            if s1[i] != s2[i]:
                return s1[:i]
        return s1

  
  

5. 最长回文子串

难度:中等
  

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。

示例 2:
?输入:s = “cbbd”
输出:“bb”

示例 3:

输入:s = “a”
输出:“a”

示例 4:

输入:s = “ac”
输出:“a”

提示:

1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成

这题是动态规划比较牛的一题,很经典。思想是把每个字符当成回文串的中心。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        self.res = ''
        def helper(i, j):
            while i >= 0 and j < n and s[i] == s[j]:
                i -= 1
                j += 1
            if len(self.res) < j - i - 1:
                self.res = s[i + 1:j]
        for i in range(n):
            helper(i, i)
            helper(i, i + 1)
        return self.res

  
  

151. 翻转字符串里的单词

难度:中等
  
给你一个字符串 s ,逐个翻转字符串中的所有 单词 。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。

说明:

输入字符串 s 可以在前面、后面或者单词间包含多余的空格。
翻转后单词间应当仅用一个空格分隔。
翻转后的字符串中不应包含额外的空格。

示例 1:

输入:s = “the sky is blue”
输出:“blue is sky the”

示例 2:

输入:s = " hello world "
输出:“world hello”
解释:输入字符串可以在前面或者后面包含多余的空格,但是翻转后的字符不能包括。

示例 3:

输入:s = “a good example”
输出:“example good a”
解释:如果两个单词间有多余的空格,将翻转后单词间的空格减少到只含一个。

示例 4:

输入:s = " Bob Loves Alice "
输出:“Alice Loves Bob”

示例 5:

输入:s = “Alice does not even like bob”
输出:“bob like even not does Alice”

提示:

1 <= s.length <= 104
s 包含英文大小写字母、数字和空格 ’ ’
s 中 至少存在一个 单词

进阶:

请尝试使用 O(1) 额外空间复杂度的原地解法。

难度应该是搞错了…

class Solution:
    def reverseWords(self, s: str) -> str:
        l = s.split()
        res = ''
        for i in l[::-1]:
            res += i
            res += ' '
        res = res.strip()
        return res

还有简单的写法

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

这题应该是想让我们用指针来做(代码也太难看了)

class Solution:
    def reverseWords(self, s: str) -> str:
        s.strip()
        s += ' '
        tmp, temp = [], []
        i, j = 0, 1
        while j < len(s):
            if s[j] == ' ':
                tmp.append(s[i:j])
                i = j
            j += 1
        for i in tmp:
            if i != ' ':
                temp.append(' ' + i.strip())
        res = ' '.join(temp[::-1])
        return res.strip()

  
  

28. 实现 strStr()

难度:简单
  
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。

说明:

当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。

示例 1:

输入:haystack = “hello”, needle = “ll”
输出:2

示例 2:

输入:haystack = “aaaaa”, needle = “bba”
输出:-1

示例 3:

输入:haystack = “”, needle = “”
输出:0

提示:

0 <= haystack.length, needle.length <= 5 * 104
haystack 和 needle 仅由小写英文字符组成

暴力搜索

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        A = len(haystack)
        B = len(needle)
        if B == 0:
            return 0
        N = A - B 
        for i in range(N + 1):
            if haystack[i:i + B] == needle:
                return i
        return -1

KMP

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        i = 0
        j = 0
        nxt = self.get_next(needle)
        while i < len(haystack) and j < len(needle):
            if haystack[i] == needle[j]:
                i += 1
                j += 1
            elif j != 0:
                j = nxt[j-1]
            else:
                i += 1
        if j == len(needle):
            return i - j
        else:
            return -1
    
    def get_next(self, substr):
        i = 1
        j = 0
        nxt = [0] * len(substr)
        while i < len(substr):
            if substr[i] == substr[j]:
                nxt[i] = j + 1
                i += 1
                j += 1
            elif j != 0:
                j = nxt[j-1]
            else:
                nxt[i] = 0
                i += 1
        return nxt

  
  

344. 反转字符串

难度:简单
  

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

示例 1:

输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]

示例 2:

输入:[“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]

注意a,b = b,a和a = b,b = a不一样,刚开始还以为是缩写,python是先计算=号的右边的值再统一赋值

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        a, b = 0, len(s) - 1
        while a < b:
            s[a], s[b] = s[b], s[a]
            a += 1
            b -= 1
        

使用reverse的我就不写了

  
  

561. 数组拆分 I

难度:简单
  

给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。
返回该 最大总和 。

示例 1:

输入:nums = [1,4,3,2]
输出:4
解释:所有可能的分法(忽略元素顺序)为:

  1. (1, 4), (2, 3) -> min(1, 4) + min(2, 3) = 1 + 2 = 3
  2. (1, 3), (2, 4) -> min(1, 3) + min(2, 4) = 1 + 2 = 3
  3. (1, 2), (3, 4) -> min(1, 2) + min(3, 4) = 1 + 3 = 4
    所以最大总和为 4

示例 2:

输入:nums = [6,2,6,5,1,2]
输出:9
解释:最优的分法为 (2, 1), (2, 5), (6, 6). min(2, 1) + min(2, 5) + min(6, 6) = 1 + 2 + 6 = 9

提示:

1 <= n <= 104
nums.length == 2 * n
-104<= nums[i] <= 104

纯数学规律

class Solution:
    def arrayPairSum(self, nums: List[int]) -> int:
        nums.sort()
        return sum(nums[::2])

  
  

167. 两数之和 II - 输入有序数组

难度:简单
  

给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。

函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。

你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

示例 2:

输入:numbers = [2,3,4], target = 6
输出:[1,3]

示例 3:

输入:numbers = [-1,0], target = -1
输出:[1,2]

提示:

2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers 按 递增顺序 排列
-1000 <= target <= 1000
仅存在一个有效答案

很简单

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        i, j = 0, len(numbers) - 1
        while i < j:
            if numbers[i] + numbers[j] > target:
                j -= 1
            elif numbers[i] + numbers[j] < target:
                i += 1
            else:
                return [i + 1, j + 1]

  
  

27. 移除元素

难度:简单
  

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

提示:

0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100

逆序pop

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        for i in range(len(nums) - 1, -1, -1):
            if nums[i] == val:
                nums.pop(i)

遍历的同时用一个慢指针记录满足

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        slow = 0
        for i in range(len(nums)):
            if nums[i] != val:
                nums[slow] = nums[i]
                slow += 1
        return slow        

  
  

485. 最大连续 1 的个数

难度:简单
  

给定一个二进制数组, 计算其中最大连续 1 的个数。

示例:

输入:[1,1,0,1,1,1]
输出:3
解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.

提示:

输入的数组只包含 0 和 1 。
输入数组的长度是正整数,且不超过 10,000。

现在原数组后面加个0然后遇到0就把计数存在res中,找res中最大的值

class Solution:
    def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
        nums.append(0)
        cnt = 0
        res = []
        for i in nums:
            if i == 1:
                cnt += 1
            else:
                res.append(cnt)
                cnt = 0
        return max(res)
class Solution:
    def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
        nums.append(0)
        cnt = 0
        res = 0
        for i in nums:
            if i == 1:
                cnt += 1
            else:
                res = max(res, cnt)
                cnt = 0
        return res

  
  

209. 长度最小的子数组

难度:简单
  

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105

双指针+滑动窗口解法
float('inf)表示正无穷

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        if not nums:
            return 0
        left, res, cur = 0, float('inf'), 0
        for right in range(len(nums)):
            cur += nums[right]
            while cur >= target:
                res = min(res, right - left + 1)
                cur -= nums[left]
                left += 1
        return res if res != float('inf') else 0

  
  

118. 杨辉三角

难度:简单
  

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

在杨辉三角中,每个数是它左上方和右上方的数的和。

示例:

输入: 5
输出:
[[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]

找到迭代的规律

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        res = [[1] * n for n in range(1, numRows + 1)]
        for i in range(2, numRows):
            for j in range(1, i):
                res[i][j] = res[i - 1][j - 1] + res[i - 1][j]
        return res

  
  

119. 杨辉三角 II

难度:简单
  

给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。

在杨辉三角中,每个数是它左上方和右上方的数的和。

示例:

输入: 3
输出: [1,3,3,1]

进阶:

你可以优化你的算法到 O(k) 空间复杂度吗?

优化前

class Solution:
    def getRow(self, rowIndex: int) -> List[int]:
        res = [[1] * n for n in range(1, 2 + rowIndex)]
        for i in range(2, 1 + rowIndex):
            for j in range(1, i):
                res[i][j] = res[i -1][j - 1] + res[i -1][j]
        return res[-1]

优化后,过程可以参考https://leetcode-cn.com/problems/pascals-triangle-ii/solution/gun-dong-shu-zu-de-dong-hua-tu-jie-you-h-rw5n/

class Solution(object):
    def getRow(self, rowIndex):
        """
        :type rowIndex: int
        :rtype: List[int]
        """
        res = [1] * (rowIndex + 1)
        for i in range(2, rowIndex + 1):
            for j in range(i - 1, 0, -1):
                res[j] += res[j - 1]
        return res
# 作者:fuxuemingzhu

  
  

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

难度:简单
  

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

示例:

输入:“Let’s take LeetCode contest”
输出:“s’teL ekat edoCteeL tsetnoc”

提示
在字符串中,每个单词由单个空格分隔,并且字符串中不会有任何额外的空格。

class Solution:
    def reverseWords(self, s: str) -> str:
        l = s.split()
        res = ''
        for i in l:
            res += i[::-1]
            res += ' '
        return res.strip()

  
  

153. 寻找旋转排序数组中的最小值

难度:中等
  

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

示例 1:

输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

示例 2:

输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。

示例 3:

输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

提示:

n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums 中的所有整数 互不相同
nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转

这种设计排序的可以考虑二分法

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

  
  

26. 删除有序数组中的重复项

难度:简单
  

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示:

0 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按升序排列

快慢指针

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        slow = 0
        for i in range(1, len(nums)):
            if nums[i] != nums[slow]:
                nums[slow + 1] = nums[i]
                slow += 1
        return slow + 1

倒序遍历,用pop

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        for i in range(len(nums) - 1, 0, -1):
            if nums[i] == nums[i -1]:
                nums.pop(i)
        return len(nums)

  
  

283. 移动零

难度:简单
  

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

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:

必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

算是上一题的延伸,先用慢指针去掉0,然后再添加0

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        slow = 0
        for i in range(len(nums)):
            if nums[i] != 0:
                nums[slow] = nums[i]
                slow += 1
        for i in range(slow, len(nums)):
            nums[i] = 0

这个快慢指针还挺难理解的,画个图最好

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        slow = 0
        for fast in range(len(nums)):
            if nums[fast] != 0:
                nums[slow], nums[fast] = nums[fast], nums[slow]
                slow += 1

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值