LeetCode精选Hot100

1.两数之和

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

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

试例

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

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        res = []
        for i in range(len(nums)):
            another_num = target - nums[i]
            if another_num in nums[i+1:]:
                res.append(i)
                res.append(nums[i+1:].index(another_num)+i)
                break
        return res
        
def twoSum(nums, target):
    lens = len(nums)
    j=-1
    for i in range(1,lens):
        temp = nums[:i]
        if (target - nums[i]) in temp:
            j = temp.index(target - nums[i])
            break
    if j>=0:
        return [j,i]

2.两数相加

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

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

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

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

两个列表同时遍历,逐位相加,保留进位 。carry保存的是进位。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        re = ListNode(0)
        r = re
        carry = 0
        while l1 or l2:
            x = l1.val if l1 else 0
            y = l2.val if l2 else 0
            sum = x + y + carry
            carry = sum // 10
            r.next = ListNode(sum % 10)
            r = r.next
            if l1 != None: l1 = l1.next
            if l2 != None: l2 = l2.next
            #当l1和l2都走到了最后,假如是5+5,那么还得需要一个ListNode(1)
            if carry > 0:
                r.next = ListNode(1)
        return re.next

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

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

示例 1:

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

示例 2:

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

示例 3:

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

index_dict记录了str[i]之前所有字符的位置

i-start+1表示子字符串的距离

start表示与上一个子字符串最后一个位置(例如:pwwkew,当i=2时候,因为两个ww,所以此时start的位置变成2,这样子算距离i-start+1才对)。start也可以解释为上一个重复字符的位置(后面那一个)

class Solution:
    def lengthOfLongestSubstring(self, str):
        """
        :type s: str
        :rtype: int
        """
        start = 0
        index_dict = {}
        max = 0
        for i in range(len(str)):
            if str[i] in index_dict and index_dict[str[i]] >= start:
                start = index_dict[str[i]] + 1
                index_dict[str[i]] = i
            else:
                index_dict[str[i]] = i
                if i-start + 1 > max:
                    max = i-start + 1
        print(index_dict)
        return max

5、最长回文子串

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

示例 1:

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

示例 2:

输入: "cbbd"
输出: "bb"

令dp[j][i]从字符串j到i是否为回文串

动态回归方程 dp[j][i]是看j+1和i-1是否为回文串.

class Solution(object):
    def longestPalindrome(self, s):
        n = len(s)

        dp = [[0] * n for _ in range(n)]
        max_len = 0
        res = ""
        for i in range(n):
            # dp[i][i] = 1
            for j in range(i, -1, -1):
                if s[i] == s[j] and (i - j < 2 or dp[i - 1][j + 1]):
                    dp[i][j] = 1

                if dp[i][j] and i - j + 1 > max_len:
                    max_len = i - j + 1
                    res = s[j:i + 1]
        # print(dp)
        return res

7、整数反转

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

示例 1:

输入: 123
输出: 321

 示例 2:

输入: -123
输出: -321

示例 3:

输入: 120
输出: 21

class Solution:
    def reverse(self, x: int) -> int:
        flag = 1 if x >= 0 else -1
        x = abs(x)
        str_x = str(x)
        str_x = str_x[::-1]
        reverse_x = int(str_x) * flag
        if -2**31 <= reverse_x <= 2**31 -1:
            return reverse_x
        else:
            return 0

8、字符串转换为整数

#-*-coding:utf-8-*-
class Solution(object):
    def myAtoi(self, str):
        """
        :type str: str
        :rtype: int
        """
        #去掉左边字符
        str=str.lstrip()
        #如果字符串空,返回
        if len(str)==0:
            return 0
        #设置默认输出为0
        last=0
        #如果有符号设置起始位置2,其余的为1
        i=2 if str[0]=='-'or str[0]=='+'  else 1
        #循环,直到无法强转成int,跳出循环
        while i <= len(str):
            try:
                last=int(str[:i])
                i+=1
            except:
                break
        #如果数字超出范围,返回范围最大值
        if last<-2147483648 :
            return -2147483648
        if last>2147483647:
            return 2147483647
        return last

 

14、最长公共前缀

输入: ["flower","flow","flight"]
输出: "fl"
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if strs == []:         # 字符串为空返回''
            return ''
        elif len(strs) == 1:   # 若列表仅有一个单词,返回该单词
            return strs[0]
        else:
            minlen = len(min(strs, key=len))  # 找到最短的单词长度
            s = ''
            for i in range(1, minlen + 1):    # 最多遍历 minlen 次
                # 每次遍历同时从每个单词取相同长度的前缀加入集合,集合中不会有重复单词
                # 列表中每个单词的相同长度前缀相同,因此集合长度为1
                if len({s[:i] for s in strs}) == 1: 
                    # 将s值更新为当前s长度与任意一个单词[:i]的部分中较大的那个值
                    # 为了避免不存在strs[1],此处默认为第一个
                    s = max(s, strs[0][:i])          
            return s

15、三数之和

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        '''
        算法思路:最外层控制一个元素的循环,
                内层用双指针,一个从头到尾扫描,另一个从尾到头扫描,判断三个元素的值之和是否为零
                
        注意:相同的元素需要跳过
        '''
        # 对列表进行排序
        nums.sort()
        res, k = [], 0
        for k in range(len(nums) - 2):
            # 如果出现最小元素为正数,则不存在和为0的情况,直接返回
            if nums[k] > 0:
                break
            # 如果出现第一个元素重复的情况,为避免重复结果,跳过后续执行
            if k > 0 and nums[k] == nums[k - 1]:
                continue
            # 定义接下来的两个元素的双指针
            i, j = k + 1, len(nums) - 1
            while i < j:
                s = nums[k] + nums[i] + nums[j]
                if s < 0:
                    i += 1
                    # 跳过重复元素
                    while i < j and nums[i] == nums[i - 1]:
                        i += 1
                elif s > 0:
                    j -= 1
                    # 跳过重复元素
                    while i < j and nums[j] == nums[j + 1]:
                        j -= 1
                else:
                    # 当出现元素满足条件是,将结果加入到列表
                    res.append([nums[k], nums[i], nums[j]])
                    # 接着更新索引(注意跳过相同元素)
                    i += 1
                    j -= 1
                    while i < j and nums[i] == nums[i - 1]:
                        i += 1
                    while i < j and nums[j] == nums[j + 1]:
                        j -= 1
        return res

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

#-*-coding:utf-8-*-
def FindKthToTail(self, head, k):
    if not head:
        return None

    pFast = head
    pSlow = head

    for i in range(k - 1):
        if pFast.next:
            pFast = pFast.next
        else:
            return None

    while pFast.next:
        pFast = pFast.next
        pSlow = pSlow.next

    return pSlow

27. 移除元素

给定 nums = [3,2,2,3], val = 3,

函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。

你不需要考虑数组中超出新长度后面的元素。

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

28、实现 strStr()

实现 strStr() 函数。

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回  -1。

输入: haystack = "hello", needle = "ll"
输出: 2
class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        n = len(haystack)
        m = len(needle)
        res = -1
        for i in range(n-m+1):
            if haystack[i:i+m] == needle:
                res =i
                break
        return res

31. 下一个排列

实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须原地修改,只允许使用额外常数空间。

以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

34、在排序数组中查找元素的第一个和最后一个位置

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]

示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

1 采用二分查找方法找到与target相等的那个下标mid,让first = last = mid;
2 找到以后,如果mid > 0并且前一个值也等于target, first = mid -1,while循环遍历一下;
3 找到以后,如果mid < 列表长度并且后一个值也等于target, last = mid +1,while循环遍历一下。
不知道时间会不会超出O(log n) ,但是仿真时间比官方题解要快。哈哈哈尴尬一笑。

# -*-coding:utf-8-*-
class Solution:
    def searchRange(self, nums, target):
        left = 0
        right = len(nums) - 1
        while left <= right:
            middle = (left + right) // 2
            if nums[middle] == target:
                m = middle
                first = last = middle
                while m < right and nums[m] == nums[m + 1]:
                    m += 1
                    last += 1
                m = middle
                while m > 0 and nums[m] == nums[m - 1]:
                    m -= 1
                    first -= 1
                return [first, last]
            elif nums[middle] < target:
                left = middle + 1
            else:
                right = middle - 1
        return [-1, -1]

38. 报数

报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:

1.     1
2.     11
3.     21
4.     1211
5.     111221

1 被读作  "one 1"  ("一个一") , 即 11。
11 被读作 "two 1s" ("两个一"), 即 21。
21 被读作 "one 2",  "one 1" ("一个二" ,  "一个一") , 即 1211。

给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。

注意:整数顺序将表示为一个字符串。

39. 组合总和

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

    所有数字(包括 target)都是正整数。
    解集不能包含重复的组合。

示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]

示例 2:

输入: candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

#-*-coding:utf-8-*-
#暴力解法
def tracp(array):
    res = 0
    for i in range(len(array)):
        l_max = max(array[0:i+1])
        r_max = max(array[i:])
        res += min(l_max, r_max) - array[i]
    return res
 
#双指针解法
def tracp1(array):
    res = 0
    left = 0;right = len(array)-1
    l_max = array[0];r_max = array[-1]
    while left <= right:
        l_max = max(l_max, array[left])
        r_max = max(r_max, array[right])
        if l_max <= r_max:
            res += l_max - array[left]
            left += 1
        else:
            res += r_max - array[right]
            right -= 1
    return res
 
array = [0,1,0,2,1,0,1,3,2,1,2,1]
res = tracp1(array)
print(res)

46.全排列

给定一个没有重复数字的序列,返回其所有可能的全排列。

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

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        def backtrack(nums, tmp):
            if not nums:
                res.append(tmp)
                return 
            for i in range(len(nums)):
                backtrack(nums[:i] + nums[i+1:], tmp + [nums[i]])
        backtrack(nums, [])
        return res

 48. 旋转图像

给定一个 n × n 的二维矩阵表示一个图像。

将图像顺时针旋转 90 度。

说明:

你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。

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

原地旋转输入矩阵,使其变为:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

# -*-coding:utf-8-*-
class Solution:
    def rotate(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: void Do not return anything, modify matrix in-place instead.
        """
        n = len(matrix[0])
        # transpose matrix
        for i in range(n):
            for j in range(i, n):
                matrix[j][i], matrix[i][j] = matrix[i][j], matrix[j][i]

        # reverse each row
        for i in range(n):
            matrix[i].reverse()
        return matrix

62.不同路径

个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

问总共有多少条不同的路径?

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        dp = [[0]*n for _ in range(m)]
        for i in range(m):
            for j in range(n):
                if i == 0 and j == 0:
                    dp[i][j] = 1
                elif i == 0: dp[i][j] = 1
                elif i == 0: dp[i][j] = 1
                else:
                    dp[i][j] = dp[i-1][j] + dp[i][j-1]
        return dp[-1][-1]

 

64. 最小路径和

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

示例:

输入:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。

 https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-dong-tai-gui-hua-gui-fan-liu-c/

class Solution:
    def minPathSum(self, grid):
        if not grid:
            return
        m = len(grid)
        n = len(grid[0])
        for i in range(m):
            for j in range(n):
                if i == 0 and j == 0:
                    continue
                elif i == 0: grid[i][j] = grid[i][j-1] + grid[i][j]
                elif j == 0: grid[i][j] = grid[i-1][j] + grid[i][j]
                else:
                    grid[i][j] = min(grid[i-1][j], grid[i][j-1]) + grid[i][j]
        return grid[-1][-1]
        

55.跳跃游戏

给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个位置。

输入: [2,3,1,1,4]
输出: true
解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。

 

70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

class Solution:
    def climbStairs(self, n: int) -> int:
        res = [1,2]
        for i in range(2, n):
            res.append(res[i-2] + res[i-1])
        return res[n-1]
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if head == None or head.next == None:
            return head
        phead = head
        while phead.next:
            if phead.val == phead.next.val:
                phead.next = phead.next.next
            else:
                phead = phead.next
        return head
发布了102 篇原创文章 · 获赞 117 · 访问量 33万+

猜你喜欢

转载自blog.csdn.net/pursuit_zhangyu/article/details/100106969