LeetCode-题库-算法:1-50(Python)

LeetCode-算法

  • 1. 两数之和
  • 2. 两数相加
  • 3. 无重复字符的最长子串
  • 4. 寻找两个有序数组的中位数
  • 5. 最长回文子串
  • 6. Z 字形变换
  • 7. 整数反转
  • 8. 字符串转换整数 (atoi)
  • 9. 回文数
  • 10. 正则表达式匹配
  • 11. 盛最多水的容器
  • 12. 整数转罗马数字
  • 13. 罗马数字转整数
  • 14. 最长公共前缀
  • 15. 三数之和
  • 16. 最接近的三数之和
  • 17. 电话号码的字母组合
  • 18. 四数之和
  • 19. 删除链表的倒数第N个节点
  • 20. 有效的括号
  • 21. 合并两个有序链表
  • 22. 括号生成
  • 23. 合并K个排序链表
  • 24. 两两交换链表中的节点
  • 25. K 个一组翻转链表
  • 26. 删除排序数组中的重复项
  • 27. 移除元素
  • 28. 实现 strStr()
  • 29. 两数相除
  • 30. 串联所有单词的子串
  • 31. 下一个排列
  • 32. 最长有效括号
  • 33. 搜索旋转排序数组
  • 34. 在排序数组中查找元素的第一个和最后一个位置
  • 35. 搜索插入位置
  • 36. 有效的数独
  • 37. 解数独
  • 38. 外观数列
  • 39. 组合总和
  • 40. 组合总和 II
  • 41. 缺失的第一个正数
  • 42. 接雨水
  • 43. 字符串相乘
  • 44. 通配符匹配
  • 45. 跳跃游戏 II
  • 46. 全排列
  • 47. 全排列 II
  • 48. 旋转图像
  • 49. 字母异位词分组
  • 50. Pow(x, n)

1. 两数之和

LeetCode-题库-算法:1-50(Python)_第1张图片

nums = [3,2,4, 3]
target = 6

思路
暴力遍历:两个循环遍历所有可能找到答案

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        nums_len = len(nums)
        for i in range(nums_len):
            for j in range(i+1, nums_len):
                if nums[i] + nums[j] == target:
                    return i, j

思路
遍历第一个数, target减去第一个数得到第二个数的值。利用nums.index()得到第二个数在数组中的索引

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        nums_len = len(nums)
        for i in range(nums_len):
            if target - nums[i] in nums and i != nums.index(target-nums[i]): 
                return i, nums.index(target-nums[i])

2. 两数相加

LeetCode-题库-算法:1-50(Python)_第2张图片

l1 = ListNode(2)
l1.next = ListNode(4)
l1.next.next = ListNode(3)
l2 = ListNode(5)
l2.next = ListNode(6)
l2.next.next = ListNode(4)
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        ans = ListNode(0)
        r = ans
        carry = 0
        while (l1 or l2):
            x = l1.val if l1 else 0
            y = l2.val if l2 else 0
            s = carry + x + y
            carry = s // 10  # 进位
            r.next = ListNode(s%10) # 将节点链接起来
            r = r.next
            if l1:
                l1 = l1.next
            if l2:
                l2 = l2.next
        if carry > 0:
            r.next = ListNode(1)
        return ans.next

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

LeetCode-题库-算法:1-50(Python)_第3张图片

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        ans = []
        maxlen = 0
        i = 0
        j = 0
        s_len = len(s)
        if s_len:
            while i < s_len:
                if s[i] in ans:
                    j = ans.index(s[i]) + 1  # s[i]在ans出现重复字符,获取ans被重复字符的位置+1
                    ans = ans[j:] # 保留重复字符后面的字符
                    ans.append(s[i])
                    i = i + 1
                else:
                    ans.append(s[i])
                    i += 1
                if len(ans) > maxlen:
                    maxlen = len(ans)        
        else:
            maxlen = 0

        return maxlen

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

LeetCode-题库-算法:1-50(Python)_第4张图片
思路
两个序列分别一个个取,计数+1,直到取到中间的数就停止

class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        len1 = len(nums1)
        len2 = len(nums2)
        len3 = len1 + len2
        nums3 = []
        mid = int((len3) / 2)
        count = 0
        while count <= mid:
            if nums1 and nums2:
                if nums1[0] <= nums2[0]:
                    nums3.append(nums1[0])
                    nums1 = nums1[1:]
                    count += 1
                else:
                    nums3.append(nums2[0])
                    nums2 = nums2[1:]
                    count += 1
            elif nums1:
                nums3.append(nums1[0])
                nums1 = nums1[1:]
                count += 1
            elif nums2:
                nums3.append(nums2[0])
                nums2 = nums2[1:]
                count += 1
        if len3 % 2 == 0:
            ans = (nums3[-1] + nums3[-2])/2.0
        else:    
            ans = float(nums3[-1])

        return ans

5. 最长回文子串

LeetCode-题库-算法:1-50(Python)_第5张图片

class Solution(object):

    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        def preProcess(s):
            ret = ""
            for i in range(len(s)):
                ret = ret + "#"+s[i]
            return "^"+ret+"#$"

        P = []
        ret = preProcess(s)  # 添加开始、结束和分隔符,使字符串始终为奇数
        n = len(ret)
        C, R = 0, 0  # 中心和右边界

        for i in range(n - 1):
            i_mirror = 2 * C - i
            if R > i:
                P.append(min(R - i, P[i_mirror]))
            else:                    # i等于右边界
                P.append(0)
                
            # 中心扩展法
            while ret[i+P[i]+1] == ret[i-P[i]-1]:
                P[i] += 1
            
            # 更新R
            if (i + P[i]) > R:
                C = i
                R = i + P[i]
            
        maxlen = 0
        centerIndex = 0
        for i in range(n - 1):
            if P[i] > maxlen:
                maxlen = P[i]
                centerIndex = i
        start = int((centerIndex - maxlen) / 2)
        
        return s[start:start + maxlen]

6. Z 字形变换

LeetCode-题库-算法:1-50(Python)_第6张图片

class Solution(object):
    def convert(self, s, numRows):
        """
        :type s: str
        :type numRows: int
        :rtype: str
        """
        n = len(s)
        if numRows < 2:
            return s
        ret = ["" for _ in range(numRows)] # 保存N字字符
        flag = -1  # 方向 1:down -1: up
        i = 0
        for c in s:
            ret[i] += c
            if i == 0 or i == numRows - 1:
                flag = -flag
            i += flag

        return "".join(ret)

7. 整数反转

LeetCode-题库-算法:1-50(Python)_第7张图片

class Solution(object):
    def reverse(self, x):
        """
        :type x: int
        :rtype: int
        """
        y = 0
        flag = 0
        if x >= -9 and x <= 9:
            y = x

        else:
            if x < 0:
                x = abs(x)
                flag = 1
            while x > 0:
                y = 10*y + x % 10
                if y > 2**31 or y < -2**31:
                    return 0
                x //= 10
        if flag:
            y = -y
        return y

8. 字符串转换整数 (atoi)

LeetCode-题库-算法:1-50(Python)_第8张图片

class Solution(object):
    def myAtoi(self, str):
        """
        :type str: str
        :rtype: int
        """
        str1 = str.strip()
        ans = ""
        for i, c in enumerate(str1):
            if (i == 0 and c == '-') or (i == 0 and c == '+') or c.isdigit():
                ans += c
            else:
                break

        if ans == "" or ans == "-" or ans == "+":
            return 0
        else:
            ans = int(ans)
            if ans > 2**31 -1:
                return 2**31 -1
            elif ans < -2**31:
                return -2**31
            else:
                return ans

9. 回文数

LeetCode-题库-算法:1-50(Python)_第9张图片

class Solution(object):
    def isPalindrome(self, x):
        """
        :type x: int
        :rtype: bool
        """
        ans = x
        y = 0
        if x < 0:
            return False
        else:
            if ans == 0:
                y = 0
            else:
                while ans > 0:
                    y = y * 10 + ans % 10
                    ans //= 10
        if y == x:
            return True
        else:
            return False

10. 正则表达式匹配

LeetCode-题库-算法:1-50(Python)_第10张图片

class Solution(object):
    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        s_len = len(s)
        p_len = len(p)
        sp = [[False] * (p_len + 1) for _ in range(s_len + 1)]

        sp[-1][-1] = True
        for i in range(s_len, -1, -1):
            for j in range(p_len - 1, -1, -1):
                match = i < s_len and p[j] in {s[i], '.'}
                if j + 1 < p_len and p[j+1] == '*':
                    sp[i][j] = sp[i][j+2] or match and sp[i+1][j]
                else:
                    sp[i][j] = match and sp[i+1][j+1] 
        return sp[0][0]

11. 盛最多水的容器

LeetCode-题库-算法:1-50(Python)_第11张图片

class Solution(object):
    def maxArea(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        Hlen = len(height)
        l = 0
        r = Hlen - 1
        maxarea = 0
        while l<r:
            w = r - l
            if height[l]< height[r]:
                h = height[l]
                l += 1
            else:
                h = height[r]
                r -= 1
            area = w * h
            maxarea = area if area > maxarea else maxarea
        
        return maxarea

12. 整数转罗马数字

LeetCode-题库-算法:1-50(Python)_第12张图片
思路
贪心法

class Solution(object):
    def intToRoman(self, num):
        """
        :type num: int
        :rtype: str
        """
        roman = [ 'M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I']
        nums = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
        ans = ''
        while num:
            for i, v in enumerate(nums):
                temp = num//v    # 除以包含的数转化为罗马数字
                if temp:
                    num -= (temp)*v
                    for _ in range(temp):
                        ans += roman[i]
        return ans

13. 罗马数字转整数

LeetCode-题库-算法:1-50(Python)_第13张图片
思路
倒序输出s,如果当前字符比前一个字符小,减去当前字符对应的数字

class Solution(object):
    def romanToInt(self, s):
        """
        :type s: str
        :rtype: int
        """
        roman = {'I':1,'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
        ans = 0
        pre = 0  # 前一个数
        for i in reversed(s):
            cur = roman[i]  # 当前数
            if cur >= pre:
                ans += cur
            else:
                ans -= cur
            pre = cur
        return ans

14. 最长公共前缀

LeetCode-题库-算法:1-50(Python)_第14张图片
思路
拿第一个字符作为标准,从头到尾的每个字符与后面的字符串中的字符做比较,全部相同则添加到前缀中

class Solution(object):
    def longestCommonPrefix(self, strs):
        """
        :type strs: List[str]
        :rtype: str
        """
        strslen = len(strs)
        prestr = ""
        flag = 1
        if strs:
            first = strs[0]
            firlen = len(first)
            for j in range(firlen):
                c = strs[0][j]
                for i in range(1, strslen):
                    if j >= len(strs[i]) or strs[i][j] != c:
                        flag = 0
                        break
                    else:
                        pass
                if flag:
                    prestr += c
                else:
                    break
        return prestr

15. 三数之和

LeetCode-题库-算法:1-50(Python)_第15张图片

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nlen = len(nums)
        nums.sort()    # 对数组排序 
        ans = list()
        i = 0
        if nlen < 3:    # 长度少于3,返回[]
            return ans
        while i < nlen - 2:    # 遍历每个数
            cur = nums[i]
            if cur > 0:
                return ans    # 第一个数大于0,返回结果 
            l = i + 1
            r = nlen - 1

            while l < r:
                if cur + nums[l] + nums[r] < 0:    # 三个数相加小于0,l往后移动
                    l += 1
                elif cur + nums[l] + nums[r] > 0:     # 三个数相加大于0,r往前移动
                    r -= 1
                else:
                    if nums[l] == nums[r]:    # 两边遇到相同的数,得到答案就可以break掉
                        ans.append([cur, nums[l], nums[r]])
                        break
                    while nums[l] == nums[l+1] and l + 1 < r:   # 跳过左边重复的数
                        l += 1
                    while nums[r] == nums[r-1] and r - 1 >l:    # 跳过右边重复的数
                        r -= 1
                    ans.append([cur, nums[l], nums[r]])
                    l += 1
                    r -= 1
            while nums[i] == nums[i+1] and i + 1 < nlen - 2:    # 第一个数重复时,跳过
                i += 1
            i += 1
        return ans

16. 最接近的三数之和

LeetCode-题库-算法:1-50(Python)_第16张图片

class Solution(object):
    def threeSumClosest(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        i, s, ans = 0, 0, 0
        nlen = len(nums)
        nums.sort()    # 对数组进行排序
        distance = sys.maxsize    # 距离target的大小,默认给最大值
        if nlen<3:
            return ans

        while i < nlen - 2:
            cur = nums[i]
            l = i + 1
            r = nlen - 1
            while l < r:    # 寻找第二、三个数
                s = cur + nums[l] + nums[r]
                temp = abs(s - target)
                if temp < distance:
                    distance = temp
                    ans = s
                if s < 0:
                    l += 1
                else:
                    r -= 1    
            i += 1
        return ans

17. 电话号码的字母组合

LeetCode-题库-算法:1-50(Python)_第17张图片

class Solution(object):
    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        KEY = {'2': ['a', 'b', 'c'],
            '3': ['d', 'e', 'f'],
            '4': ['g', 'h', 'i'],
            '5': ['j', 'k', 'l'],
            '6': ['m', 'n', 'o'],
            '7': ['p', 'q', 'r', 's'],
            '8': ['t', 'u', 'v'],
            '9': ['w', 'x', 'y', 'z']}
        if not digits:
            return []
        ans = ['']
        for num in digits:
            ans = [pre+cur for pre in ans for cur in KEY[num]]
        return ans

18. 四数之和

LeetCode-题库-算法:1-50(Python)_第18张图片

class Solution(object):
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        nums.sort()
        nlen = len(nums)
        ans = list()
        i = 0
        if nlen < 4:
            return ans
        while i < nlen - 3:    # 遍历第一个数
            j = i + 1
            while j < nlen - 2:    # 遍历第二个数
                l = j + 1
                r = nlen - 1
                while l < r:    # 寻找第三、四个数
                    if nums[i] + nums[j] + nums[l] + nums[r] < target and l < r:    # 总和比target小,l往右移动
                        l += 1
                    elif nums[i] + nums[j] + nums[l] + nums[r] > target and l < r:    # 总和比target大,r往右移动
                        r -= 1
                    else:
                        if nums[l] == nums[r]:    # 总和相等时,第三、四个数相同,终止遍历
                            ans.append([nums[i], nums[j], nums[l], nums[r]])
                            break
                        while nums[l] == nums[l+1] and l+1 < r:    # 第三个数重复,跳过
                            l += 1
                        while nums[r] == nums[r-1] and r-1 > l:    # 第四个数重复,跳过
                            r -= 1
                        ans.append([nums[i], nums[j], nums[l], nums[r]])
                        l += 1
                        r -= 1
                while nums[j] == nums[j+1] and j + 1 < nlen - 2:    # 第二个数重复,跳过
                    j += 1   
                j += 1
            while nums[i] == nums[i+1] and i + 1 < nlen - 3:    # 第一个数重复,跳过
                i += 1
            i += 1
        return ans

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

LeetCode-题库-算法:1-50(Python)_第19张图片

head = ListNode(1)
temp = head
for i in range(2, 6):
    temp.next = ListNode(i)
    temp = temp.next
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        first = head
        second = head
        if n == 0:
            return head

        for _ in range(n):    # 第一个指针先走n步
            if first.next != None:
                first = first.next 
            else:    # 走到最后一个数
                first = head
        # 第一个指针走到末尾,第二个指针跟第一个距离为n,第二个指针指向下下个结点,去除倒数第n个结点
        while first.next != None:    
            first = first.next
            second = second.next
        if second.next == None:    # 删除第一个
            second = head
            second = second.next
            head = second
        elif second.next.next == None:    # 删除倒数第一个
            second.next = None
        else:
            second.next = second.next.next
        return head

20. 有效的括号

LeetCode-题库-算法:1-50(Python)_第20张图片
思路

  • 队列:FIFO=先进先出 LIFO=后入先出
    使用LIFO,遍历所有字符,遇到左括号则放进队列里,遇到右括号则将左括号取出,检查左右括号是否一对,直到队列为空
class Solution(object):
    def isValid(self, s):
        """
        :type s: str
        :rtype: bool
        """
        left = list()
        if not s:
            return True
        for c in s:
            if c in ['(', '[', '{']:
                left.append(c)
            else:
                if not left:
                    return False
                else:
                    l = left.pop()
                    if (l == '(' and c == ')') or (l == '[' and c == ']') or (l == '{' and c == '}'):
                        pass
                    else:    
                        return False
        if left:
            return False
        else:
            return True

21. 合并两个有序链表

LeetCode-题库-算法:1-50(Python)_第21张图片

l1 = ListNode(1)
l1.next = ListNode(2)
l1.next.next = ListNode(4)
l2 = ListNode(1)
l2.next = ListNode(3)
l2.next.next = ListNode(4)

思路
两个链表对比大小,把较小的数放在新链表里

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

class Solution(object):
    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        anshead = ListNode(-1)    
        ans = anshead
        while l1 != None and l2 != None:
            if l1.val <= l2.val:
                ans.next = l1
                l1 = l1.next
                ans = ans.next
            else:
                ans.next = l2
                l2 = l2.next
                ans = ans.next
        if l1 != None:
            ans.next = l1
        elif l2 != None:
            ans.next = l2
        return anshead.next

思路
递归两个链表

class Solution(object):
    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        if l2 is None:
            return l1
        elif l1 is None:
            return l2
        elif l1.val <= l2.val:
            l1.next = self.mergeTwoLists(l1.next, l2)
            return l1
        else:
            l2.next = self.mergeTwoLists(l1, l2.next)
            return l2   

22. 括号生成

LeetCode-题库-算法:1-50(Python)_第22张图片
思路
递归,添加少于n个左括号,右括号少于左括号个数时添加

class Solution(object):
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        ans = list()
        def valid(S='', left=0, right=0):
            if len(S) == 2 * n:
                ans.append(S)
                return ans
            if left < n:
                valid(S+'(', left+1, right)
            if right < left:
                valid(S+')', left, right+1)
        valid()
        return ans

23. 合并K个排序链表

LeetCode-题库-算法:1-50(Python)_第23张图片

lists = list()
l1 = ListNode(1)
l1.next = ListNode(4)
l1.next.next = ListNode(5)
l2 = ListNode(1)
l2.next = ListNode(3)
l2.next.next = ListNode(4)
l3 = ListNode(2)
l3.next = ListNode(6)
lists.append(l1)
lists.append(l2)
lists.append(l3)

思路
暴力法:将所有数放在一个数组里,再进行排序,再形成链表

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

class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        anshead = ListNode(-1)
        ans = anshead
        llen = len(lists)
        nums = list()
        for i in range(llen):
            l = lists[i]
            while l != None:
                nums.append(l.val)
                l = l.next
        nums.sort()
        for n in nums:
            ans.next = ListNode(n)
            ans = ans.next
        return anshead.next

24. 两两交换链表中的节点

LeetCode-题库-算法:1-50(Python)_第24张图片

head = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(3)
head.next.next.next = ListNode(4)

思路
递归交换

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

class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        def sw(head):
            if head == None or head.next == None:
                return head
            n = head.next
            head.next = sw(n.next)
            n.next = head
            return n
        return sw(head)

思路
创建一个头部指向head
LeetCode-题库-算法:1-50(Python)_第25张图片

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

class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        pre = ListNode(-1)
        pre.next = head    # 1
        h = pre
        while h.next != None and h.next.next != None:
            first = h.next    # 2
            second = h.next.next    # 3
            h.next = second    # 4
            first.next = second.next    # 5
            second.next = first    # 6
            h = first    # 7
        return pre.next

25. K 个一组翻转链表

LeetCode-题库-算法:1-50(Python)_第26张图片
思路

  1. 当链表长度大于k时,将k长度的放进列表里(堆),然后进行翻转
  2. 当链表剩下长度小于k的,直接连接在后面
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def reverseKGroup(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        pre = ListNode(-1)
        p = pre
        while True:
            count = k
            h = head
            temp = list()
            while count and h:
                temp.append(h)
                h = h.next
                count -= 1
            if count:    # 链表长度少于k
                p.next = head
                break
            while temp:    # 链表长度大于k时,翻转链表
                p.next = temp.pop()
                p = p.next
            p.next = h
            head = h
        return pre.next

思路

  1. 当链表长度大于k时,tail指向第k个数,分别将数字插入到tail后面翻转k个链表
  2. 当链表剩余长度小于k时,将剩余部分连接起来
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def reverseKGroup(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        pre = ListNode(-1)
        pre.next = head
        p = pre
        tail = pre
        while True:
            count = k
            while count and tail:
                count -= 1
                tail = tail.next
            if not tail:
                break
            head = p.next
            while p.next != tail:
                cur = p.next
                p.next = cur.next
                cur.next = tail.next
                tail.next = cur
            p = head
            tail = head
        return pre.next

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

LeetCode-题库-算法:1-50(Python)_第27张图片
思路
使用set去重,但空间复杂度为O(n),不符合题意

class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        temp = list(set(nums))
        tlen = len(temp)
        temp.sort()
        for i in range(tlen):
            nums[i] = temp[i]
        return tlen

思路
双指针

class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nlen = len(nums)
        if not nums:
            return 0
        i = 0
        for j in range(1, nlen):
            if nums[i] != nums[j]:
                i += 1
                nums[i] = nums[j]
        return i+1

27. 移除元素

LeetCode-题库-算法:1-50(Python)_第28张图片
思路
将等于val的数字pop掉

class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        nlen = len(nums)
        i = 0
        while i < len(nums):
            if nums[i] == val:
                nums.pop(i)
                continue
            i += 1
        return len(nums)

思路
双指针:重头到位遍历,保存不等于val的数字

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

28. 实现 strStr()

LeetCode-题库-算法:1-50(Python)_第29张图片
思路
显而易见

class Solution(object):
    def strStr(self, haystack, needle):
        """
        :type haystack: str
        :type needle: str
        :rtype: int
        """
        return haystack.index(needle) if needle in haystack else -1

29. 两数相除

LeetCode-题库-算法:1-50(Python)_第30张图片
思路
移位运算:乘(左移);除(右移),一位是2

class Solution(object):
    def divide(self, dividend, divisor):
        """
        :type dividend: int
        :type divisor: int
        :rtype: int
        """
        sign = (dividend > 0) ^ (divisor > 0)
        dividend = abs(dividend)
        divisor = abs(divisor)
        count = 0
        while dividend >= divisor:
            count += 1
            divisor <<= 1    # 左移,每次乘以2,知道大于被除数
        ans = 0
        while count:
            count -= 1
            divisor >>= 1
            if divisor <= dividend:
                ans += 1<<count # 左移将二进制转为十进制
                dividend -= divisor
        if sign:
            ans = -ans
        return ans if -(1<<31) <= ans <= (1<<31)-1 else (1<<31)-1

30. 串联所有单词的子串

LeetCode-题库-算法:1-50(Python)_第31张图片
思路

  1. 在s截取words总长度的stemp,遍历stemp将长度为word的字符,添加至temp里
  2. words,temp的字符和出现次数形成哈希表,两者相等则返回起始下标i
class Solution(object):
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
        from collections import Counter
        ans = list()
        if not s or not words:
            return ans
        wlen = len(words[0])
        wslen = len(words) * wlen
        slen = len(s)
        words = Counter(words)
        for i in range(slen - wslen + 1):
            stemp = s[i:i+wslen]
            temp = list()
            for j in range(0, wslen, wlen):
                temp.append(stemp[j:j+wlen])
            if Counter(temp) == words:
                ans.append(i)
        return ans

31. 下一个排列

LeetCode-题库-算法:1-50(Python)_第32张图片
思路

  1. 如果为空数组或长度为1的数组直接返回
  2. 如果找到数组中前一个小于后一个的数字,下标为i-1(nums[i-1]
  3. 如果i>0,即nums[i-1]稍大的数与nums[i-1]交换
  4. 由2得出,i-1后面数字为降序排序,头部与尾部对换,使其变为升序排序
class Solution(object):
    def nextPermutation(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        nlen = len(nums)
        flag = 0
        if nlen == 0 or nlen == 1:
            return nums
            
        i = nlen - 1
        while i > 0 and nums[i-1] >= nums[i]:
            i -= 1

        if i > 0:    # 数组里前面有小于后面的数
            j = nlen - 1
            while j > i-1 and nums[j] <= nums[i-1]:
                j -= 1   
            nums[i-1], nums[j] = nums[j], nums[i-1]

        start = i
        last = nlen-1
        while start < last:
            nums[start], nums[last] = nums[last], nums[start]
            start += 1
            last -= 1
        return nums

32. 最长有效括号

LeetCode-题库-算法:1-50(Python)_第33张图片
思路

  1. 建立长度为字符串s长度的数组,初始化为0
  2. 遇到右括号时查看前一个字符,如果是左括号,长度加2,如果是右括号,减去前一个括号的连续字符长度再减1,查看是否左括号与其对应,如果是,2(增加的有效括号长度)+dp[i-1](前一个右括号的有效长度)+dp[i-dp[i-1]-2](与当前右括号对应的左括号前一个括号的有效长度)
    LeetCode-题库-算法:1-50(Python)_第34张图片
class Solution(object):
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        # 1
        slen = len(s)
        dp = [0]*slen
        for i in range(1, slen):
            if s[i] == ')':
                if s[i-1] == '(':
                    dp[i] = dp[i-2] + 2 if i > 2 else 2
                elif s[i-1] == ')' and i - dp[i-1] > 0 and s[i-dp[i-1]-1] == '(':
                    dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2
        return max(dp)

思路

  1. 从左往右遍历一次,记下左、右括号数,相等时计算长度,大于最大长度时更新,遇到左括号数小于右括号数时,长度清零,如())(),到第二个右括号时,括号不连续,长度清零
  2. 从右往左遍历一次,记下左、右括号数,相等时计算长度,大于最大长度时更新,遇到右括号数小于左括号数时,长度清零,如()((),到第二个左括号时,括号不连续,长度清零
class Solution(object):
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        slen = len(s)
        left, right = 0, 0
        maxlen = 0
        for i in range(slen):
            if s[i] == '(':
                left += 1
            else:
                right += 1
                if left == right:
                    templen = left + right
                    if templen > maxlen:
                        maxlen = templen
                elif left < right:
                    templen = 0
                    left, right = 0, 0
        left, right = 0, 0
        for j in range(slen-1, -1, -1):
            if s[j] == ")":
                right += 1
            else:
                left += 1
                if left == right:
                    templen = left + right
                    if templen > maxlen:
                        maxlen = templen
                elif right < left:
                    templen = 0
                    left, right = 0, 0
        return maxlen

33. 搜索旋转排序数组

LeetCode-题库-算法:1-50(Python)_第35张图片
思路

  1. 二分查找最小的数为数组有序的分界点
  2. target小于最小的数返回-1
  3. target大于等于数组第一个数,则target可能存在数组左边有序序列中,否则target可能存在数组右边有序序列中
  4. 在有序序列中使用二分查找target
class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        # 查找最小的数
        def findmin(nums, l, r):
            if nums[l] <= nums[r]:
                return l
            while l <= r:
                m = (l+r)//2
                if nums[m] > nums[m+1]:
                    return m+1
                else:
                    if nums[m] > nums[l]:
                        l = m+1
                    else:
                        r = m  
        # 二分查看
        def binary(nums, l, r, target):
            while l <= r:
                mid = (l+r)//2
                if nums[mid] == target:
                    return mid
                elif nums[mid] > target:
                    r = mid - 1
                else:
                    l = mid + 1
            return -1

        nlen = len(nums)
        l, r = 0, nlen - 1
        if not nums:
            return -1
        if nlen == 1:
            return 0 if target == nums[0] else -1
        # 1
        mini = findmin(nums, l, r)
        # mini在第一位,直接使用二分查找
        if mini == l:
            return binary(nums, l, r, target)
        # 2
        if target < nums[mini]:
            return -1
        # 3 4
        if target >= nums[l]:
            return binary(nums, l, mini-1, target)
        else:
            return binary(nums, mini, r, target)

思路
O(∩_∩)O哈哈~

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        return nums.index(target) if target in nums else -1

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

LeetCode-题库-算法:1-50(Python)_第36张图片
思路

  1. 二分查找target
  2. 往左和右边寻找相同的数,移动下标
class Solution(object):
    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        if not nums:
            return [-1, -1]
        def binary(nums, l, r, target):
            while l <= r:
                m = (l+r)//2
                if nums[m] == target:
                    return m
                elif nums[m] > target:
                    r = m - 1
                else:
                    l = m + 1
            return -1
        nlen = len(nums)
        l, r = 0, nlen - 1
        # 1
        index = binary(nums, l, r, target)
        start,end = index, index
        # 2
        if index != -1:    # target存在数组中
            while start-1 >= l and nums[start-1] == nums[start]:
                start -= 1
            while end+1 <= r and nums[end+1] == nums[end]:
                end += 1
        return [start, end]

35. 搜索插入位置

LeetCode-题库-算法:1-50(Python)_第37张图片
思路
二分查找,找到target返回下标,找不到返回l的位置即为插入位置

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

36. 有效的数独

LeetCode-题库-算法:1-50(Python)_第38张图片

board = [
    ["5","3",".",".","7",".",".",".","."],
    ["6",".",".","1","9","5",".",".","."],
    [".","9","8",".",".",".",".","6","."],
    ["8",".",".",".","6",".",".",".","3"],
    ["4",".",".","8",".","3",".",".","1"],
    ["7",".",".",".","2",".",".",".","6"],
    [".","6",".",".",".",".","2","8","."],
    [".",".",".","4","1","9",".",".","5"],
    [".",".",".",".","8",".",".","7","9"]
]

思路
行、列、小矩阵遍历是否有重复的数,如果已经存在,即返回False;遍历结束,没有相同即返回True
确定小矩阵index

i j box_idx
0-2 0-2 0
0-2 3-5 1
0-2 6-8 2
3-5 0-2 3
3-5 3-5 4
3-5 6-8 5
6-8 0-2 6
6-8 3-5 7
6-8 6-8 8

由此可得:box_idx = (i//3)*3+j//3

class Solution(object):
    def isValidSudoku(self, board):
        """
        :type board: List[List[str]]
        :rtype: bool
        """
        rows = [[] for _ in range(9)]
        columns = [[] for _ in range(9)]
        boxes = [[] for _ in range(9)]
        for i in range(9):
            for j in range(9):
                num = board[i][j]
                if board[i][j] != '.':
                    box_idx = (i//3)*3+j//3
                    if num not in rows[i] and num not in columns[j] and num not in boxes[box_idx]:
                        rows[i].append(num)
                        columns[j].append(num)
                        boxes[box_idx].append(num)
                    else:
                        return False
        return True

37. 解数独

LeetCode-题库-算法:1-50(Python)_第39张图片

board = [
    ["5","3",".",".","7",".",".",".","."],
    ["6",".",".","1","9","5",".",".","."],
    [".","9","8",".",".",".",".","6","."],
    ["8",".",".",".","6",".",".",".","3"],
    ["4",".",".","8",".","3",".",".","1"],
    ["7",".",".",".","2",".",".",".","6"],
    [".","6",".",".",".",".","2","8","."],
    [".",".",".","4","1","9",".",".","5"],
    [".",".",".",".","8",".",".","7","9"]
]

思路

  1. 建立数组行、列、小方格,将已有的数字,对应的下标设为1,没有的数字设置为0
  2. 回溯法
class Solution(object):
    def solveSudoku(self, board):
        """
        :type board: List[List[str]]
        :rtype: None Do not return anything, modify board in-place instead.
        """
        
        def delnum(num, i, j):
            rows[i][num] = 0
            columns[j][num] = 0
            box_id = (i//3)*3+j//3
            boxes[box_id][num] = 0
            
        def fillnum(num, i, j):
            rows[i][num] += 1
            columns[j][num] += 1
            box_id = (i//3)*3+j//3
            boxes[box_id][num] += 1
                    
        def solve(row, col):
            if row == 9 and col == 0:    # 回溯结束的条件
                return True
            if board[row][col] == '.':
                box_id = (row//3)*3+col//3
                for num in range(1, 10):
                    if rows[row][num]==0 and columns[col][num]==0 and boxes[box_id][num]==0:
                        fillnum(num, row, col)
                        board[row][col] = str(num)
                        ans = solve(row+1, 0) if col == 8 else solve(row, col+1)
                        if ans:
                            return True
                        if not ans:    # 回溯时清除已填的错误数字
                            delnum(int(num), row, col)
                            board[row][col] = '.'
            else:
                ans = solve(row+1, 0) if col == 8 else solve(row, col+1)
                if ans:
                    return True

        # 1            
        rows = [[0 for _ in range(10)] for _ in range(9)]
        columns = [[0 for _ in range(10)] for _ in range(9)]
        boxes =  [[0 for _ in range(10)] for _ in range(9)]

        for i in range(9):
            for j in range(9):
                if board[i][j] != '.':
                    fillnum(int(board[i][j]), i, j)
        # 2
        solve(0, 0)
        return board

38. 外观数列

LeetCode-题库-算法:1-50(Python)_第40张图片
思路
递归:上一次得到的结果作为输入

class Solution(object):
    def countAndSay(self, n):
        """
        :type n: int
        :rtype: str
        """

        if n == 1:
            return "1"
        nums = self.countAndSay(n-1)    # 上一次得到的结果作为输入
        nlen = len(nums)
        count = 1
        re = ""
        for i in range(nlen-1):
            if nums[i] == nums[i+1]:
                count += 1
            else:
                re = re + str(count) + nums[i]
                count = 1
        re = re + str(count) + nums[nlen-1]
        return re

39. 组合总和

LeetCode-题库-算法:1-50(Python)_第41张图片
思路
回溯

class Solution(object):
    def combinationSum(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """

        candidates.sort()
        clen = len(candidates)
        ans = list()
        def solve(index, sub, sumn):
            if sumn == target:
                ans.append(sub)
                return
            if sumn > target or index == clen:
                return
            if sumn+candidates[index] <= target:    # 剪枝
                solve(index, sub+[candidates[index]], sumn+candidates[index])
                solve(index+1, sub, sumn)
        
        solve(0, [], 0)
        return ans

40. 组合总和 II

LeetCode-题库-算法:1-50(Python)_第42张图片
思路
回溯

class Solution(object):
    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        candidates.sort()
        clen = len(candidates)
        ans = list()

        def solve(index, sub, sumn):
            if sumn == target:
                if sub not in ans:    # 去重
                    ans.append(sub)
                return
            if sumn > target or index == clen:
                return
            if sumn + candidates[index] <= target:    # 剪枝
                solve(index + 1, sub + [candidates[index]], sumn + candidates[index])     # 加上当前值,并把索引指向下一个数字
                solve(index + 1, sub, sumn)    
        
        solve(0, [], 0)
        return ans

41. 缺失的第一个正数

LeetCode-题库-算法:1-50(Python)_第43张图片
思路
根据数组长度去寻找没有出现在数字中的正整数

class Solution(object):
    def firstMissingPositive(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nlen = len(nums)
        if not nlen:
            return 1
        for i in range(1, nlen+1):
            if i not in nums:
                return i
        return nlen + 1

42. 接雨水

LeetCode-题库-算法:1-50(Python)_第44张图片
思路
双指针:

  1. 下标分别指向最左侧l和最右侧r
  2. 分别保存左边和右边最高的数字(柱子)left_max, right_max
  3. 左侧柱子小于右侧柱子时,左侧往右遍历,小于left_max时,left_max减去当前柱子高度,累加到ans中
  4. 右侧柱子小于等于左侧柱子时,右侧往左遍历,小于right_max时,right_max减去当前柱子高度,累加到ans中
  5. 左右侧下标相遇时,结束遍历,返回ans
class Solution(object):
    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """

        hlen = len(height)
        l, r = 0, hlen - 1
        ans = 0
        if hlen == 0:
            return 0
        left_max = height[l]
        right_max = height[r]
        while l < r:
            if height[l] < height[r]:
                if height[l] > left_max:
                    left_max = height[l]
                else:
                    ans += left_max - height[l]
                l += 1
            else:
                if height[r] > right_max:
                    right_max = height[r]
                else:
                    ans += right_max - height[r]
                r -= 1    
        return ans

43. 字符串相乘

LeetCode-题库-算法:1-50(Python)_第45张图片
思路
映射为数字

class Solution(object):
    def multiply(self, num1, num2):
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """
        mapping = {
            '0': 0,
            '1': 1,
            '2': 2,
            '3': 3,
            '4': 4,
            '5': 5,
            '6': 6,
            '7': 7,
            '8': 8,
            '9': 9
        }
        n1len, n2len = len(num1), len(num2)
        tmp1, tmp2 = 0, 0
        for i in num1:
            tmp1 = tmp1*10 + mapping[i]
        for j in num2:
            tmp2 = tmp2*10 + mapping[j]
        return (str(tmp1*tmp2))

44. 通配符匹配

LeetCode-题库-算法:1-50(Python)_第46张图片
思路
双指针

  1. s[i]和p[j]匹配,或p[j]==’?’, i/j加1
  2. p[j]==’*’,标记位置,匹配空字符或j+1与s中寻找匹配的字符
  3. s匹配结束后,查看p是否有剩余字符,剩余字符是否为*,是为True,否则为False
class Solution(object):
    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        slen, plen = len(s), len(p)
        start = -1
        match = 0
        i, j = 0, 0
        while i < slen:
            if j < plen and (s[i] == p[j] or p[j] == '?'):
                i += 1
                j += 1
            elif j < plen and p[j] == '*':
                start = j
                match = i
                j += 1
            elif start != -1:
                j = start +1
                match += 1
                i = match    
            else:
                return False
        return all(x == "*" for x in p[j:])

45. 跳跃游戏 II

LeetCode-题库-算法:1-50(Python)_第47张图片
思路
step跳跃一次,end等于能到达的最大位置,如果end走到nums最后或大于nums位置,则完成跳跃

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nlen = len(nums)
        step = 0
        end, maxindex = 0, 0
        for i in range(0, nlen-1):
            maxindex = max(i + nums[i], maxindex)
            if i == end:
                step += 1
                end = maxindex
                if end >= nlen-1:
                    return step
        return step

46. 全排列

LeetCode-题库-算法:1-50(Python)_第48张图片
思路

  1. 求所有可能出现在第一个位置的字符,即把第一个字符和后面的所有字符交换
  2. 然后固定第一个字符,求后面所有字符的排序
  3. 把后面的字符看成两部分,第一个字符和后面的字符,然后重复上述步骤(递归,归的终止条件是需要处理的字符长度为 1)
class Solution(object):
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        if len(nums) <= 1:
            return [nums]
        temp = []
        for i in range(len(nums)):
            for j in self.permute(nums[0:i]+nums[i+1:]):
                temp.append([nums[i]] + j)
        return temp

47. 全排列 II

LeetCode-题库-算法:1-50(Python)_第49张图片
思路

  1. 求所有可能出现在第一个位置的字符,即把第一个字符和后面的所有字符交换
  2. 然后固定第一个字符,求后面所有字符的排序
  3. 把后面的字符看成两部分,第一个字符和后面的字符,然后重复上述步骤(递归,归的终止条件是需要处理的字符长度为 1)
  4. 剪枝:出现已经作为第一个数的情况就剪枝
class Solution(object):
    def permuteUnique(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        if len(nums) <= 1:
            return [nums]
        ans = []
        first = []
        for i in range(len(nums)):
            if nums[i] not in first:    # 剪枝
                first.append(nums[i])
            else:
                continue
            for j in self.permuteUnique(nums[0:i]+nums[i+1:]):
                ans.append([nums[i]] + j)
        return ans

48. 旋转图像

LeetCode-题库-算法:1-50(Python)_第50张图片
思路

  1. 使用数组保存旋转后的数组
  2. 赋值给原来的数组
class Solution(object):
    def rotate(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: None Do not return anything, modify matrix in-place instead.
        """
        row = len(matrix)
        col = len(matrix[0])
        ans = [[] for _ in range(row)]
        for i in range(row):
            for j in range(col):
                ans[i].append(matrix[col-j-1][i])
        for i in range(row):
            for j in range(col):
                matrix[i][j] = ans[i][j]
        return matrix

49. 字母异位词分组

LeetCode-题库-算法:1-50(Python)_第51张图片
思路
创建字典,用sorted辨识字母相同的作为key,对应的词添加到value中

class Solution(object):
    def groupAnagrams(self, strs):
        """
        :type strs: List[str]
        :rtype: List[List[str]]
        """
        ans = dict()
        for s in strs:
            sort_s = sorted(s)
            key = ''.join(sort_s)
            if key not in ans.keys():
                ans[key] = [s]
            else:
                ans[key].append(s)
        return list(ans.values())

50. Pow(x, n)

LeetCode-题库-算法:1-50(Python)_第52张图片
思路
暴力破解会提示“MemoryError”

  1. n n n为负数时:
    x = 1 x x = {1 \over x} x=x1
    n = − n n = -n n=n
  2. n n n分解一下:
    x n 2 × x n 2 = x n x^{n\over2}\times x^{n\over2}=x^n x2n×x2n=xn
  3. n n n为偶数时:
    x n 2 = A , x n = A × A x^{n\over2}=A, x^n = A\times A x2n=A,xn=A×A
  4. n n n为奇数时:
    n n n除以2 得到余数1
    x n 2 = A , x n − 1 = A × A x^{n\over2}=A, x^{n-1} = A\times A x2n=A,xn1=A×A
    最后再乘以一个 x x x就行
class Solution(object):
    def myPow(self, x, n):
        """
        :type x: float
        :type n: int
        :rtype: float
        """
        def halfPow(x,n):
            if n == 0:
                return 1.0
            half = halfPow(x,n//2)
            if n%2 == 0:
                return half*half
            else:
                return half*half*x

        if n < 0:
            x = 1.0/x
            n = -n
            
        return halfPow(x, n)

你可能感兴趣的:(LeetCode-题库-算法:1-50(Python))