leetcode刷题记录1-50-基于python

1.两数之和-Easy

class Solution():
	def twoSum(self, nums, target):
		# nums: list->int
		# target: 两数之和
		# 遍历数组每一个元素
		for i in nums:
			# 计算另一个数
			j = target - i 
			# 记录下开始索引
			start_index = nums.index(i)
			# 将i后面的数存放在一个临时list,防止出现6 = 3+3
			temp = nums[start_index + 1:]
			# 判断另一个数是否在该数组中
			if j in temp:
				# 输出
				return (start_index , start_index + 1 + temp.index(j))

优化

class Solution():
	def TwoSum(self, nums, target):
		# 存储形式为{values:index, ...,}
		dict = {}
		for i in range(len(nums)):
			if (target - nums[i]) not in dict:
				dict[nums[i]] = i
			else:
				return [dict[target - nums[i]], i]

2.两数相加-Medium

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        # 判断l1或者l2是否存在
        if l1 == None:
            return l2
        if l2 == None:
            return l1

        dummy = ListNode(0)
        p = dummy
        carry = 0

        # 若l1 和 l2存在,进行计算
        while l1 and l2:
            # 当前位相加后的值,carry为进位
            p.next = ListNode((l1.val + l2.val + carry ) % 10)
            carry = (l1.val + l2.val + carry) // 10
            # 改变指针指向下一个节点
            l1 = l1.next
            l2 = l2.next
            p = p.next

        # 若l1 长度 < l2长度,相加完后,l2还有多余数据,进行相加
        if l2:
            while l2:
                p.next = ListNode((l2.val + carry) % 10)
                carry = (l2.val + carry) // 10
                l2 = l2.next
                p = p.next
        # 若l1 长度 > l2
        if l1:
            while l1:
                p.next = ListNode((l1.val + carry) % 10)
                carry = (l1.val + carry) // 10
                l1 = l1.next
                p = p.next
        # 若最后carry仍为1
        if carry == 1:
            p.next = ListNode(1)
        return dummy.next

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

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 本质{'char1':index1, 'char2':index2...}
        # 求上一个重复点到下一个重复点最大差值
        start = -1
        max = 0
        dict = {}
        for i in range(len(s)):
            if s[i] in dict and dict[s[i]] > start:
                start = dict[s[i]]
                dict[s[i]] = i
            else:
                dict[s[i]] = i
                if i - start > max:
                    max = i - start
        return max

4.寻找两个正序数组的中位数-Hard

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        m = len(nums1)
        n = len(nums2)
        total = m + n

        i = total // 2
        j = total // 2 - int(total & 1 == 0)

        return (self.findKtn(nums1, m, nums2, n, i + 1) + self.findKtn(nums1, m, nums2, n, j + 1)) / 2


    def findKtn(self, nums1, m, nums2, n, k):
        if m > n:
            return self.findKtn(nums2, n, nums1, m, k)
        if m == 0:
            return nums2[k - 1]
        if k == 1:
            return min(nums1[0], nums2[0])
        p1 = min(k // 2, m)
        p2 = k - p1
        if nums1[p1 - 1] < nums2[p2 - 1]:
            return self.findKtn(nums1[p1:], m - p1, nums2, n, k - p1)
        elif nums1[p1 - 1] > nums2[p2 - 1]:
            return self.findKtn(nums1, m, nums2[p2:], n - p2, k - p2)
        else:
             return nums1[p1 - 1]

5. 最长回文子串-Medium

class Solution:
    def longestPalindrome(self, s: str) -> str:
        # 定义一个空字符串,存储找到的回文子串
        palindrome = ''
        # 遍历字符串中每一个字符
        for i in range(len(s)):
            # 获取回文子串的长度,以最中间单个字母为中心
            len1 = len(self.getLongestPalindrome(s, i, i))
            # len1不为空或者大于已找到回文子串长度,说明找到了新的回文子串
            if len1 > len(palindrome):
                palindrome = self.getLongestPalindrome(s, i, i)
            # 获取回文子串长度,以最中间两个字母为中心
            len2 = len(self.getLongestPalindrome(s, i, i+1))
            if len2 > len(palindrome):
                palindrome = self.getLongestPalindrome(s, i, i+1)
        return palindrome


    # 判断是否为需要的回文子串
    def getLongestPalindrome(self, s, l, r):
        # s: 要判断的字符串
        # l: 该字符串最左侧字符
        # r: 该字符串最右侧字符
        # s[l] == s[r] 为一个回文子串
        while l >= 0 and r < len(s) and s[l] == s[r]:
            # 向左边右边扩充字符,判断是否依旧满足条件
            l -= 1 
            r += 1
        # 返回找到的回文子串
        return s[l+1 : r]

6.Z 字形变换-Medium

class Solution:
    def convert(self, s: str, numRows: int) -> str:
        # s = "PAYPALISHIRING", numRows = 3
        # iter :1, 'P', row[0]
        #                   +1
        # iter :2, 'A', row[1]
        #                   +1
        # iter :3, 'Y', row[2]
        #                   +1
        # iter :4, 'P', row[1]
        #                   -1 
        # iter :5, 'A', row[0]
        #                   -1    
        # iter :6, 'L', row[1]
        #                   +1
        # iter :7, 'I', row[2]
        #                   +1
        # ...
        # 规律
        # 当row == 0: step = 1
        # 当row == numRows - 1, step = -1
        # row += step
        

        # 判断str长度是否不满足zigzag形式
        if len(s) < numRows or numRows == 1:
            return s
        # 初始化行索引和步长
        row, step = 0, 1
        # 初始化存储结果列表
        zigzag = ['' for x in range(numRows)]
        # 遍历并按规则进行存储每个字符
        for char_ in s:
            zigzag[row] += char_
            # 存储一个字符后,对行索引进行更新
            if row == 0:
                step = 1
            elif row == numRows - 1:
                step = -1
            row += step
        # 返回拼接字符串
        return ''.join(zigzag)         

7. 整数反转-Easy

class Solution:
    def reverse(self, x: int) -> int:
        # 有符号整数范围:-2147483648~2147483647
        # 定义一个初始变量,用于存储取出来的每一位整数
        num = 0
        # 获取输入整数的绝对值
        x_ = abs(x)
        while(x_ != 0):
            # 从最后一位开始取值
            temp = x_ % 10
            # 每取一个值,需要向前移一个位,因此:
            num = num * 10 + temp
            # 更新已移除个位的原整数
            x_ = int(x_ / 10)
        # 判断整数是否越界及原本符号
        if x >= 0 and num < 2147483647:
            return num
        elif x < 0 and num <= 2147483648:
            return -num
        else:
            return 0

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

class Solution:
    def myAtoi(self, s: str) -> int:
        # 对输入字符串进行去空
        stripS = s.strip()
        # 判断是否为'-','+',''等单个字符
        if stripS == '-' or stripS == '' or stripS == '+':
            return 0
        # 在去除左侧符号后,判断是否存在除了数字以外的内容
        # re.match() 从头开始匹配到结束
        s1 = re.match('[^\d]+', (stripS.lstrip('-')).lstrip('+'))
        if s1 != None:
            return 0
        else:
            # 提取包含符号在内的数字部分
            # re.search()匹配到满足规则为止
            # group()提取匹配到的结果
            s1 = re.search(r'[-|+]*\d+', stripS).group()
        # 若前两位为'--','++','-+'
        if s1[0:2] == '--' or s1[0:2] == '++' or s1[0:2] == '-+':
            return 0
        # 去掉符号
        res = int(s1)
        # 判断是否越界
        if res > 0:
            return 2147483647 if res > 2147483647 else res
        else:
            return -2147483648 if res < -2147483648 else res

9.回文数-Easy

class Solution:
    def isPalindrome(self, x: int) -> bool:
        # 定义一个变量用于存储反转后的数字
        num = 0
        # 对原整数取绝对值
        x_ = abs(x)
        # 依次按位进行反转
        while(x_ != 0):
            # 一个临时变量存储每次需要反转的位置上的数
            temp = x_ % 10
            # 将该值放在相应位置
            num = num * 10 + temp
            # 去除已反转位置上的数
            # x_ = int(x_ / 10)
            x_ = x_ // 10
        # 判断是否为回文数
        if x >= 0 and x == num:
            return True
        else:
            return False

10. 正则表达式匹配-Hard

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        cache = [[False] * (len(s) + 1) for _ in range(len(p) + 1)]
        cache[0][0] = True
        for i in range(1, len(p)):
            cache[i + 1][0] = cache[i - 1][0] and p[i] == '*'
        for i in range(len(p)):
            for j in range(len(s)):
                if p[i] == '*':
                    cache[i + 1][j + 1] = cache[i][j + 1] or cache[i - 1][j + 1]
                    if p[i - 1] == s[j] or p[i - 1] == '.':
                        cache[i + 1][j + 1] |= cache[i + 1][j]
                else:
                    cache[i + 1][j + 1] = cache[i][j] and (p[i] == s[j] or p[i] == '.')
        return  cache[-1][-1]

11.盛最多水的容器-Medium

class Solution(object):
    def maxArea(self, height: List[int]) -> int:
        # 初始化左右指针,表示当前位置
        left = 0
        right = len(height) - 1
        # 初始化面积
        res = 0
        # 左右移动,并计算面积,直到左右指针相遇
        # 若使用!= : left = 3, right = 2 这样是不合逻辑的
        while (left < right):
            # 面积 = 当前左右位置高度的最小值 * 左右指针的距离
            area = min(height[left], height[right]) * (right - left)
            # 当前面积如果大于上一次面积,则进行赋值
            if area > res:
                res = area
            # 判断下一次该左移还是右移,原则尽可能保留较大的高度(保证面积最大),高度较低的位置进行移动
            if height[left] < height[right]:
                left += 1
            else:
                right -= 1
        return res

12. 整数转罗马数字-Medium

class Solution:
    def intToRoman(self, num: int) -> str:
        # values = [100, 900, 500, 400..]
        # numerals = ['M', 'CM', 'D', 'CD', ..]
        # input = 1994
        # 1994 > 1000 ? => M
        # 994 > 900 ? => MCM
        # 94> 90 ? => MCMXC
        # 4 > 5 ? => MCMXCIV
        values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
        numerals = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I' ]
        # 取values中的值 与输入num 依次判断位于哪个区间,并拼接numerals中的值
        result = ''
        for i in range(0, len(values)):
            while num >= values[i]:
                result += numerals[i]
                # 拼接完成后,对num进行更新,减去最高位,降低一位再次进行比较
                num -= values[i]
        return result

13. 罗马数字转整数-Easy

class Solution:
    def romanToInt(self, s: str) -> int:
        # 判断两个相邻字母,左边的字母必小于右边字母代表的数字,则认为他们是一对组合,值为后面字母值-前面字母的值
        # 定义一个字符和数值对照的字典
        numeral_map = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
        # 初始化最终结果
        result = 0
        # 遍历字符串的每个字母
        for i in range(len(s)):
            # 识别出的每个字母对应的数字进行相加,即为最后的结果
            # 但是 若前一个字母小于后一个字母,则认为他们是一组,需要进行相减
            # 识别出的第一个和第二个字母  :result = M + C
            # 当为第二和第三个字母时,由于CM C<M :temp = M - C
            # 前三个字母最终的结果:result += M - C
            # 即 result = M + C + M - C = M + M
            # 而 expected_res = M + (M - C)
            # 因此 temp = M - 2C => result = M + M - C  
            if i > 0 and numeral_map[s[i]] > numeral_map[s[i - 1]]:
                result += numeral_map[s[i]] - 2 * numeral_map[s[i - 1]]
            else:
                result += numeral_map[s[i]]
        return result

14. 最长公共前缀-Easy

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        # 首先判断是否是一个str
        if not strs:
            return ''
        # 以list中第一个str为基准(公共前缀最大只会等于某一个单词长度,因此以第一个为基准即可))
        for i in range(len(strs[0])):
            # 从第二个单词开始 每个字符进行比较
            for string in strs[1:]:
                # 若当前单词长度超过与之比较的单词长度
                # 或者没有找到公共前缀时
                # 若strs = ["flower","flow","flight"]
                # strs[0] => flower string[0][0] =>f
                # string => flow string[0] => f
                if i >= len(string) or string[i] != strs[0][i]:
                    # strs[0][:i] 截取开始到索引i位置的字母,但不包括i
                    return strs[0][:i]
        # 若该字符为空即'',其本身也为str,直接返回该值本身即可
        return strs[0]

或者

def longestCommonPrefix(self, strs: List[str]) -> str:
            # 保存最后结果变量
            result = ''
            i = 0
            while True:
                try:
                    # 采用集合类型(该变量类型会自动去重并保留唯一一个不重复的变量)
                    # 遍历每个单词的每个字母,并使用set去重
                    sets = set(string[i] for string in strs)
                    # 若每次返回长度为1,则表示该位置为公共前缀
                    # 若strs = ["flower","flow","flight"]
                    # i = 0,sets = {'f'} len = 1
                    # i = 1, sets = {'l'} len = 1
                    # i = 2, sets = {'o','i'} len = 2
                    if len(sets) == 1:
                        # 索引+1遍历下一个字母
                        i += 1
                        # 拼接结果,需要用pop()进行取值
                        result += sets.pop()
                    else:
                        # 长度不为1 ,则表明当前位置的字符并非公共前缀的部分
                        break
                except Exception as e:
                    break
            return result

15. 三数之和-Medium

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 获取list 长度
        n = len(nums)
        # 初始化存储结果list
        result = []
        # 对list 进行排序
        # sorted() 函数->sorted(list) 返回新list,原list无变化
        # sort() list方法-> 直接原list修改
        nums.sort()
        
        # 由于要求为三数之和等于0
        for i in range(n-2):
            # list以从小到大方式排列,若前三数相加仍大于0,那这个list不会组合为三数为0的情况(最小三数都大于0,更大的数必然为正)
            if nums[i] + nums[i+1] + nums[i+2] > 0:
                break
            # 若最小数和最大的两个数相加仍为负,那有可能存在等于0的情况
            if nums[i] + nums[n-2] + nums[n-1] < 0:
                continue
            # 不包含重复的三元组
            if i > 0 and nums[i] == nums[i-1]:
                continue
            # 初始化左右指针,加快查找速度
            l, r = i + 1, n - 1
            while l < r:
                tmp = nums[i] + nums[l] + nums[r]
                if tmp == 0:
                    # 满足条件存储结果
                    result.append([nums[i], nums[l], nums[r]])
                    while l+1 < r and nums[l] == nums[l+1]:
                        # 若遇到相等的值,则继续向右边查找
                        l += 1
                    # 更新外部l的值
                    l += 1
                    while r - 1 > l and nums[r] == [r-1]:
                        r -=1
                    r -= 1
                elif tmp < 0:
                    # tmp<0说明左边值过小,右移
                    l += 1
                else:
                    # 说明右边值过大,左移
                    r -= 1
        return result                    

16. 最接近的三数之和-Medium

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        # 对list进行排序
        nums = sorted(nums)
        # 初始化一个result
        result = nums[0] + nums[1] + nums[len(nums) - 1]
        # 遍历list中每个数,组合为三数之和
        for i in range(len(nums) - 2):
            # 当找到第二个及以后值时,判断当前找到的值是否和前一个相等
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            # 初始化左右指针
            l = i + 1
            r = len(nums) - 1
            while l < r:
                # 计算当前val
                val = nums[l] + nums[i] + nums[r]
                # 判断当前值是否小于初始值,若是,则进行重新赋值
                if abs(val - target) < abs(result - target):
                    result = val
                # 若差值刚好与目标值target相等,说明找到了
                if val == target:
                    return target
                # 若差值小于目标值,说明左边值过小,左移
                elif val < target:
                    l += 1
                # 若差值过大,说明右边值过大,右移
                else:
                    r -= 1
        return result

17. 电话号码的字母组合-Medium

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        # 判断输入digits是否为空
        if len(digits) == 0:
            return []
        # 定义一个数字与字母对应的dict
        digits_map = {
            0:'0',
            1:'1',
            2:'abc',
            3:'def',
            4:'ghi',
            5:'jkl',
            6:'mno',
            7:'pqrs',
            8:'tuv',
            9:'wxyz'
        }
        result = ['']
        # 遍历每个输入数字,并取出dict中对应字母
        for digit in digits:
            # 定义一个list存放每次查找的结果
            tmp_list = []
            # 根据每个key查找每个对应字母的value,digit ->str
            for ch in digits_map[int(digit)]:
                # 将先前找到的字母与接下来找到的字母进行组合
                for str in result:
                    tmp_list.append(str + ch)
            result = tmp_list
        return result

18. 四数之和-Medium

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        # 判断list 是否不足4个元素
        if len(nums) < 4:
            return []
        # 对list 进行排序
        nums.sort()
        # 结果采用hash(自动去重) 
        ans = set()
        # 遍历元素
        for i in range(len(nums) - 3):
            for j in range(i + 1, len(nums) - 2):
                # 记录下当前两个值的和
                now = nums[i] + nums[j]
                # 定义左右指针
                l = j + 1
                r = len(nums) - 1
                while l < r:
                    # 判断是否满足条件
                    if nums[l] + now + nums[r] == target:
                        # 判断是否是重复元素
                        if (nums[i], nums[j], nums[l], nums[r]) not in ans:
                            # set()使用add()添加元素
                            ans.add((nums[i], nums[j], nums[l], nums[r]))
                    if nums[l] + now + nums[r] > target:
                        r -= 1
                    else:
                        l += 1
        # 最终结果转换为list
        return list(ans)

19. 删除链表的倒数第 N 个结点-Medium

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        dummy = ListNode(0)
        # 定义头结点
        dummy.next = head
        # 定义快慢指针
        slow = fast = dummy
        # 先让快指针移动n步
        for _ in range(n):
            fast = fast.next
        # 此时移动慢指针
        while fast.next:
            slow = slow.next
            fast = fast.next
        # 移除要移除的节点
        slow.next = slow.next.next
        # 返回头结点
        return dummy.next

20. 有效的括号-Easy

class Solution:
    def isValid(self, s: str) -> bool:
        # 定义一个list存储每个字符
        stack = []
        # 定义每个括号对应的dict
        lookup = {'(':')', '[':']', '{':'}'}
        # 遍历每个字符
        for ch in s:
            if ch in lookup:
                stack.append(ch)
            elif len(stack) == 0 or lookup[stack.pop()] != ch:
                return False

        return len(stack) == 0

21. 合并两个有序链表-Easy

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        curr = dummy = ListNode(0)
        while l1 and l2:
            # 判断 将值按从小到大进行插入
            if l1.val < l2.val:
                curr.next = l1
                l1 = l1.next
            else:
                curr.next = l2
                l2 = l2.next
            curr = curr.next
        curr.next = l1 or l2
        return dummy.next

22. 括号生成-Medium

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        # 输入为空,直接返回
        if n == 0:
            return []

        result = []
        self.helper(n, n, '', result)
        return result

    def helper(self, l, r, item, result):
        # 括号数量不匹配
        if r < l:
            return 
        # 将左右边遍历完的括号添加入结果
        if l == 0 and r == 0:
            result.append(item)
        # 查找(
        if l > 0:
            self.helper(l-1, r, item + '(', result)
        if r > 0:
            self.helper(l, r-1, item + ')', result)
        

23. 合并K个升序链表-Hard

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

    def __eq__(self, other):
        return self.l.val == other.l.val

    def __lt__(self, other):
        return self.l.val < other.l.val


class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        dummy = ListNode(0)
        curr = dummy

        heap = [MyListNode(i) for i in lists if i]
        heapq.heapify(heap)

        while heap:
            i = heapq.heappop(heap).l
            curr.next = ListNode(i.val)
            curr = curr.next

            if i.next:
                heapq.heappush(heap, MyListNode(i.next))
        return dummy.next

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

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        # 判断是否不存在节点或者只有一个节点
        if not head or not head.next:
            return head
        
        p = head
        new_start = p.next
        while(True):
            # 两两交换
            q = p.next 
            temp = q.next 
            q.next = p

            # 判断是否存在下两个节点
            if not temp or not temp.next:
                p.next = temp
                break
            p.next = temp.next
            p = temp
        return new_start

25. K 个一组翻转链表-Hard

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
        dumb = ListNode(10086)
        dumb.next = head
        end = prev = dumb
        

        def swap(prev, k, end):
            after = end.next
            move = prev.next 
            prev.next = end
            temp = move.next
            end = move 

            for i in range(k - 1):
                tnext = temp.next
                temp.next = move
                move = temp  
                temp = tnext
            end.next = after
            return end

        while True:
            try:
                for _ in range(k):
                    end = end.next
                prev = end = swap(prev, k, end)
            except:
                break
        return dumb.next

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

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        # 判断list是否为空
        if not nums:
            return 0
        # 初始化一个计数变量
        count = 0
        # 遍历元素
        for i in range(len(nums)):
            # 若元素不相等,count +1
            # 本质将不重复元素都移至list前面
            if nums[count] != nums[i]:
                count += 1
                # 同时更新基准值
                nums[count] = nums[i]
        # 返回长度
        return count + 1

27. 移除元素-Easy

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 初始化左右指针
        start, end = 0, len(nums) - 1
        # 进行比较,若左右指针的某元素等于val,将该元素交换到尾部,进行删除
        while start <= end:
            if nums[start] == val:
                nums[start], nums[end] = nums[end], nums[start]
                # 删除最后一个元素(在这里并不是真的删除,end指针-1)
                end -= 1
            else:
                # 若start指针元素与最后一个元素不等,则继续查找下一个
                start += 1
        return end + 1

28. 实现 strStr()-Easy

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        # 遍历haystack
        for i in range(len(haystack) - len(needle) + 1):
            # 判断是否相等,每次移动needle长度
            if haystack[i : i + len(needle)] == needle:
                return i
        return -1

29. 两数相除-Medium

位运算

class Solution:
    def divide(self, dividend: int, divisor: int) -> int:
        # 二进制运算,从右至左,每一位的数*2的[0,(n-1)]次方
        # 二进制左移:右边补0-->左移后比原来数大2倍
        # 位运算
        flag = -1 if (dividend > 0 and divisor < 0) or ((dividend < 0 and divisor > 0)) else 1
        dividend, divisor = abs(dividend), abs(divisor)
        q, times = 0, 0
        while dividend >= divisor:
            cur = dividend - (divisor << times)
            
            if cur >= 0:
                q += (1 << times)
                times += 1
                dividend = cur 

            else:
                times -= 1
        return max(-2 ** 31, min(q * flag, 2 ** 31-1))

30. 串联所有单词的子串-Hard

class Solution:
    def findSubstring(self, s: str, words: List[str]) -> List[int]:
        if len(words) == 0: return []
        unilen = len(words[0])
        res, sets = [], {}
        for word in words:
            sets[word] = sets.setdefault(word, 0) + 1
        
        for i in range(unilen):
            count, start, match_set = len(words), i, {}
            for j in range(i, len(s), unilen):
                substr = s[j : j+unilen]
                if substr in sets:
                    match_set[substr] = match_set.setdefault(substr, 0) + 1
                    count -= 1
                    while (match_set[substr] > sets[substr]):
                        remove = s[start : start + unilen]
                        start += unilen
                        match_set[remove] -= 1
                        count += 1
                    if count == 0:
                        res.append(start)
                else:
                    count, start, match_set = len(words), j + unilen, {}
        return res

31. 下一个排列-Medium

class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        if sorted(nums, reverse = True) == nums:
            nums[:] = nums[::-1]
            return 
        for i in range(len(nums) - 1)[::-1]:
            if nums[i] < nums[i + 1]:
                break
        for j in range(i + 1, len(nums)):
            if j == len(nums) - 1 or nums[j + 1] <= nums[i]:
                nums[i], nums[j] = nums[j], nums[i]
                break
        nums[i + 1:] = nums[i + 1:][::-1]
        return 

32. 最长有效括号-Hard

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        res = 0
        stack = [-1]
        for i, c in enumerate(s):
            if c == '(':
                stack.append(i)
            elif len(stack) == 1:
                stack.pop()
                stack.append(i)
            else:
                stack.pop()
                res = max(res, i - stack[-1])
        return res 

33. 搜索旋转排序数组-Medium

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        # 采用二分查找的思想
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] == target:
                return mid
            if target >= nums[0]:
                if nums[mid] >= nums[0] and target > nums[mid]:
                    left = mid + 1
                else:
                    right = mid - 1
            else:
                if nums[mid] >= nums[0] or target > nums[mid]:
                    left = mid + 1
                else:
                    right = mid - 1
        return -1

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

bisect模块

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        from bisect import bisect_left, bisect_right
        if len(nums) == 0: return [-1, -1]
        res = [-1, -1]
        left = bisect_left(nums, target)
        if left < len(nums) and nums[left] == target:
            res[0] = left
            res[1] = bisect_right(nums, target) - 1
        return res 
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        try:
        	return [nums.index(target), len(nums) - (list(nums[::-1]).index(target))-1]
        except:
        	return [-1, -1]

35. 搜索插入位置-Easy

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        # 若target大于list中所有数,则它被插入到最后,索引为list长度
        if target > nums[-1]:
            return len(nums)
        # 遍历所有元素
        for i in range(len(nums)):
            # 按顺序插入target,并返回其索引
            if nums[i] >= target:
                return i   

36. 有效的数独-Medium

class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        return self.is_row_valid(board) and self.is_col_valid(board) and self.is_sqare_valid(board)

    
    # 数字 1-9 在每一行只能出现一次
    def is_row_valid(self, board):
        for row in board:
            if not self.is_unit_valid(row):
                return False
        return True


    # 数字 1-9 在每一列只能出现一次
    def is_col_valid(self, board):
        print(board) # [['5', '3', '.', '.', '7', '.', '.', '.', '.'], ['6', '.', '.', '1', '9', '5', '.', '.', '.'], ...]
        for col in zip(*board):
            print(col) # ('5', '6', '.', '8', '4', '7', '.', '.', '.')


            if not self.is_unit_valid(col):
                return False
        return True


    # 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次
    def is_sqare_valid(self, board):
        # 以[0,0] = 5 为例,按行 下一个粗线区域为[0,3],下下个为[0,6]
        for i in (0, 3, 6):
            # 同理,每列对应相对位置
            for j in (0, 3, 6):
                sqare = [board[x][y] for x in range(i, i + 3) for y in range(j, j + 3)]
                if not self.is_unit_valid(sqare):
                    return False
        return True


    # 数独部分空格内已填入了数字,空白格用 '.' 表示。
    def is_unit_valid(self, unit):
        unit = [i for i in unit if i != '.']
        return len(set(unit)) == len(unit)

37. 解数独-Hard

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        r3, r9, s9 = range(3), range(9), set(str(x) for x in range(1, 10))
        def dfs():
            for i, row in enumerate(board):
                for j, char in enumerate(row):
                    if char != '.': continue
                    for x in s9-{row[k] for k in r9} - {board[k][j] for k in r9} - {board[i//3*3+m][j//3*3+n] for m in r3 for n in r3}:
                        board[i][j] = x
                        if dfs(): return True
                        board[i][j] = '.'
                    return False
            return True
        dfs()

38. 外观数列-Easy

class Solution:
    def countAndSay(self, n: int) -> str:
        # 定义起始字符
        seq = '1'
        # 计算每一行的输出值
        for i in range(n-1):
            seq = self.getNext(seq)
        return seq


    def getNext(self, seq):
        i, next_seq = 0, ''
        while i < len(seq):
            count = 1
            while i < len(seq) - 1 and seq[i] == seq[i + 1]:
                count += 1
                i += 1
            next_seq += str(count) + seq[i]
            i += 1
        return next_seq

39. 组合总和-Medium

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        result = []
        candidates.sort()
        self._combinationSum(candidates, target, 0, [], result)
        return result

    def _combinationSum(self, nums, target, index, path, res):
        if target < 0:
            return 

        if target == 0:
            res.append(path)
            return 
        for i in range(index, len(nums)):
            self._combinationSum(nums, target - nums[i], i, path + [nums[i]], res)

40. 组合总和II-Medium

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        if not candidates:
            return []
    

        def dfs(start_index, candidates, target, path, res):
            if target == 0:
                res.append(copy.deepcopy(path))
                return
            for i in range(start_index, len(candidates)):
                if candidates[i] <= target:
                    if i > start_index and candidates[i] == candidates[i - 1]:
                        continue
                    path.append(candidates[i])
                    dfs(i + 1, candidates, target - candidates[i], path, res)
                    path.pop()
        
        candidates.sort()
        path = []
        res = []
        start_index = 0
        dfs(start_index, candidates, target, path, res)
        return res

41. 缺失的第一个正数-Hard

class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        # 定义首尾元素
        nums += [2 ** 31] * 2
        # 去除小于0或者大于length的元素
        for i in range(len(nums)):
            if nums[i] < 0 or nums[i] >= len(nums):
                nums[i] = 0
        # 将所有元素标记为负数,0标记为-cur
        for i in range(len(nums)):
            cur = abs(nums[i])
            if nums[cur] == 0:
                nums[cur] = -cur
            else:
                nums[cur] = -1 * abs(nums[cur])

        # 返回结果
        for i in range(1, len(nums)):
            if nums[i] >= 0:
                return i

42. 接雨水-Hard

class Solution:
    def trap(self, height: List[int]) -> int:
        if len(height) == 0 or max(height) == 0: return 0
        self.res = 0
        max_ = max(height)
        index = height.index(max_)
        self.area(height[:index])
        self.area(height[index + 1:][::-1])
        return self.res
 

    def area(self, h):
        if len(h) == 0 or max(h) == 0: return 
        maxh = max(h)
        index = h.index(maxh)
        self.res += ((len(h) - index - 1) * maxh - sum(h[index + 1:]))
        self.area(h[:index])

43. 字符串相乘-Medium

class Solution:
    def multiply(self, num1: str, num2: str) -> str:
        if num1 == '0' or num2 == '0':
            return '0'

        if len(num1) < len(num2):
            num1, num2 = num2, num1
        num1 = num1[::-1]
        num2 = num2[::-1]

        add_list = []
        for i in range(len(num2)):
            for j in range(len(num1)):
                newnum2_i = int(num2[i] + '0' * i)
                newnum1_j = int(num1[j] + '0' * j)
                add_list.append(newnum1_j * newnum2_i)
        return str(sum(add_list))

44. 通配符匹配-Hard

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        # 初始化匹配索引
        cache = [-1, -1]
        p_ptr, s_ptr = 0, 0
        while s_ptr < len(s):
            if p_ptr < len(p) and p[p_ptr] in (s[s_ptr], '*', '?'):
                if p[p_ptr] =='*':
                    cache[0], cache[1] = p_ptr, s_ptr
                else:
                    s_ptr += 1
                p_ptr += 1
            elif cache[0] != -1:
                p_ptr, s_ptr = cache[0] + 1, cache[1] + 1
                cache[1] += 1
            else:
                return False
        while p_ptr < len(p) and p[p_ptr] =='*':
            p_ptr += 1
        return (p_ptr == len(p))

45. 跳跃游戏 II-Medium

class Solution:
    def jump(self, nums: List[int]) -> int:
        if len(nums) == 0:
            return 0

        step = 0
        left = 0
        right = 0
        for i in range(len(nums) - 1):
            right = max(right, i + nums[i])
            if i == left:
                step += 1
                left = right
        return step

46. 全排列-Medium

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        # 判断list本身是否唯一元素
        if len(nums) <= 1:
            return [nums]
        ans = []
        for i, num in enumerate(nums):
            n = nums[:i] + nums[i+1:]
            # print(i,n)
            # 0 [2, 3]
            # 0 [3]
            # 1 [2]
            # 1 [1, 3]
            # 0 [3]
            # 1 [1]
            # 2 [1, 2]
            # 0 [2]
            # 1 [1]

            for y in self.permute(n):
                ans.append([num] + y)
        return ans

47. 全排列 II-Medium

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        if len(nums) == 0: return [[]]
        res = [[]]
        for n in nums:
            temp = []
            for r in res:
                for i in range(len(r) + 1):
                    temp.append(r[:i] + [n] + r[i:])
                    if i < len(r) and r[i] == n:
                        break
                res = temp
        return res

48. 旋转图像-Medium

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

49. 字母异位词分组-Medium

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        # 利用dict进行存储每一个类别
        solution = {}
        # 多创建一个列表是由于leetcode提交原因
        res = []
        # 判断是否为一个元素
        if len(strs) < 1: 
            return strs
        else:
            # 遍历list中每个char 
            for i in range(len(strs)):
                reg = strs[i]
                # 对每个char的所有字母进行排序后拼接 判断其是否为一个组
                regsort = ''.join(sorted(reg))
                # 判断dict中是否存在该组,存在直接存储,不存在创建组
                if regsort in solution:
                    solution[regsort].append(reg)
                else:
                    solution[regsort] = [reg]
        # return solution.values()
        for val in solution.values():
            res.append(val)
        return res

50. Pow(x, n)-Medium

class Solution:
    # 方式1
    # def myPow(self, x: float, n: int) -> float:
    #     return x ** n 
    def myPow(self, x: float, n: int) -> float:
        # 2**10
        # 10-> 二进制:1010:2^3 + 2^1
        # 即 2**10:2^8 * 2^2
        if n < 0:
            return 1/self.myPow(x, -n)
        res = 1
        track = x
        while n>0:
            # 判断n的最右侧是否为1
            if n&1:
                res *= track
            track *= track
            # 二进制右移一位
            n >>= 1
        return res
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值