leetcode热题系列14

540. 有序数组中的单一元素

给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。

示例 1:
输入: [1,1,2,3,3,4,4,8,8]
输出: 2

示例 2:
输入: [3,3,7,7,10,11,11]
输出: 10

思路:
利用逻辑运算XOR的性质AAB=B。

class Solution(object):
    def singleNonDuplicate(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        i = 0
        for num in nums:
            i ^= num
        return i

301. 删除无效的括号

给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。

示例 1:
输入:s = “()())()”
输出:[“(())()”,“()()()”]

示例 2:
输入:s = “(a)())()”
输出:[“(a())()”,“(a)()()”]

示例 3:
输入:s = “)(”
输出:[“”]

class Solution:
    def removeInvalidParentheses(self, s: str) -> List[str]:
        res = []
        lremove, rremove = 0, 0
        for c in s:
            if c == "(":
                lremove += 1
            elif c == ")":
                if lremove == 0:
                    rremove += 1
                else:
                    lremove -= 1
        
        def isValid(ss):
            cnt = 0
            for c in ss:
                if c == "(":
                    cnt += 1
                elif c == ")":
                    cnt -= 1
                    if cnt < 0:
                        return False 
            return cnt == 0

        def dfs(s, start, lremove, rremove):
            if lremove == 0 and rremove == 0:
                if isValid(s):
                    res.append(s)
                return

            for i in range(start, len(s)):
                if i > start and s[i] == s[i-1]:
                    continue 
                if lremove + rremove > len(s) - i: # 剪枝
                    break 
                if lremove > 0 and s[i] == "(":
                    dfs(s[:i]+s[i+1:], i, lremove-1,rremove)
                if rremove > 0 and s[i] == ")":
                    dfs(s[:i]+s[i+1:], i, lremove, rremove-1)

        dfs(s, 0, lremove, rremove)
        return res          

437. 路径总和 III

给定一个二叉树的根节点root,和一个整数targetSum,求该二叉树里节点值之和等于targetSum的路径的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

示例 1:
输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示。

示例 2:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:3

提示:
二叉树的节点个数的范围是 [0,1000]
-10^9 <= Node.val <= 10^9
-1000 <= targetSum <= 1000
在这里插入图片描述

class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        def rootSum(root, targetSum):
            if root is None:
                return 0

            ret = 0
            if root.val == targetSum:
                ret += 1

            ret += rootSum(root.left, targetSum - root.val)
            ret += rootSum(root.right, targetSum - root.val)
            return ret
        
        if root is None:
            return 0
            
        ret = rootSum(root, targetSum) #以root为根节点进行计算,也就是在这个函数里面不管怎样计算sum,都是会带上root的值
        ret += self.pathSum(root.left, targetSum) #注意这里是pathSum函数,相当于是另一棵树了
        ret += self.pathSum(root.right, targetSum)
        return ret

204. 计数质数

输入: 10
输出: 4
解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
要注意的是1不是质数哦!!

先将2-N的各数放入表中,然后在2的上面画一个圆圈,然后划去2的其他倍数;第一个既未画圈又没有被划去的数是3,将它画圈,再划去3的其他倍数;现在既未画圈又没有被划去的第一个数 是5,将它画圈,并划去5的其他倍数……依次类推,一直到所有小于或等于N的各数都画了圈或划去为止。这时,表中画了圈的以及未划去的那些数正好就是小于 N的素数。

class Solution:
    def countPrimes(self, n: int) -> int:
        isPrimes = [1] * n
        res = 0
        for i in range(2, n):
            if isPrimes[i] == 1: res += 1
            j = i
            while i * j < n:
                isPrimes[i * j] = 0
                j += 1
        return res

补充题21. 字符串相减

如果你还没做过415. 字符串相加,建议先做一下。减法比加法稍微麻烦一点,但核心思路相似。

题目描述
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的差。

注意:

num1 和num2 都只会包含数字 0-9
num1 和num2 都不包含任何前导零
你不能使用任何內建 BigInteger 库
题目分析
两个非负整数相减的结果可能为负。

因此,首先比较两个数的大小。

如代码所示,当小减大时,需将两个参数调换一下位置执行减法,在结果前填上负号即可

注意:结果为0时不加负号。

def sub(a, b):
    res = ""
    borrow = 0
    i, j = len(a) - 1, len(b) - 1
    while i >= 0 or j >= 0:
        x = int(a[i]) if i >= 0 else 0
        y = int(b[j]) if j >= 0 else 0
        z = (x - borrow - y + 10) % 10
        res += str(z)
        borrow = 1 if x - borrow - y < 0 else 0
        i -= 1
        j -= 1
    res = res[::-1]
    # 删除前导0。循环条件是len(res)-1是为防止"0000"的情况
    pos = 0
    while pos < len(res) - 1 and res[pos] == '0':
        pos += 1
    return res[pos:]

def cmp(a, b):
    if len(a) == len(b):
        return a < b
    return len(a) < len(b)

def sub_strings(num1, num2):
    if cmp(num1, num2):
        res = sub(num2, num1)
        if res != "0":
            res = "-" + res
    else:
        res = sub(num1, num2)
    return res

if __name__ == "__main__":
    a = input()
    b = input()
    print(sub_strings(a, b))

567. 字符串的排列

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。

示例1:
输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).

示例2:
输入: s1= “ab” s2 = “eidboaoo”
输出: False

注意:
输入的字符串只包含小写字母
两个字符串的长度都在 [1, 10,000] 之间

思路
最开始使用的是全排列,然后比较的时候发现T了,然后就想到用排序的方式,emmmm又T了。 最后想到用滑动窗口 然后A了
每次取 s1 长度的窗口 然后排序比较,相等就返回True

class Solution(object):
    def checkInclusion(self, s1, s2):
        """
        :type s1: str
        :type s2: str
        :rtype: bool
        """
        l1,l2 = len(s1),len(s2)
        s1 = sorted(s1)
        for i in range(l2-l1+1):
            t = s2[i:i+l1]
            if sorted(t) == s1:
                return True
        return False

剑指 Offer 46. 把数字翻译成字符串

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。
一个数字可能有多个翻译。
请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", “bwfi”, “bczi”, “mcfi"和"mzi”

1.将输入num从int型转为str snum,dpres保存结果,dp[i]表示snum[0:i-1]有多少种组合方式。

dp[0]=0,dp[1]=0(对应snum[0]一个字符,只有一种方法),要注意dpres的下标比snum大1。

2.对snum的第i-1个字符进行判断:

如果snum[i-2]+snum[i-1]<26并且snum[i-2]不为0(避免06 05这样不合法的情况),则dpres[i]=dpres[i-1]+dpres[i-2],因为第i-1个字符有自己单独翻译为一个字母以及和前面一个字符一起翻译两种选择。

如果不满足以上条件,说明snum[i-1]只有单独翻译一个选项,dpres[i]=dpres[i-1]

class Solution(object):
    def translateNum(self, num):
        dpres = []
        dpres.append(1)
        dpres.append(1)
        snum = str(num)
        if len(snum)<=1:
            return 1
        for i in range(2,len(snum)+1):
            if snum[i-2]+snum[i-1]<"26" and snum[i-2]!='0':
                dpres.append(dpres[i-1]+dpres[i-2])
            else:
                dpres.append(dpres[i-1])
        return dpres[len(snum)]

面试题 08.12. 八皇后

171. Excel表列序号

class solution(object):
    def titleToNumber(self, s: str) -> int:
        # 理解为26进制的转化
        # 初始化结果 ans = 0,遍历时将每个字母与 A 做减法,因为 A 表示 1,所以减法后需要每个数加 1,计算其代表的数值 num = 字母 - ‘A’ + 1. 因为有 26 个字母,所以相当于 26 进制,每 26 个数则向前进一位. 所以每遍历一位则ans = ans * 26 + num. 以 ZY 为例,Z 的值为 26,Y 的值为 25,则结果为 26 * 26 + 25=701.
        ans = 0
        for i in range(len(s)):   #遍历每个字符
            #ord()函数返回对应的十进制整数。
            num = ord(s[i]) - ord('A') + 1  #将字符转化为数字  例如Z则为26
            ans = ans * 26 + num
        return ans


a = 'ZY'
c = solution()
b = c.titleToNumber(a)
print(b)
#时间复杂度O(n),空间复杂度:O(1)

525. 连续数组

给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。

示例 1:

输入: nums = [0,1]
输出: 2
说明: [0, 1] 是具有相同数量0和1的最长连续子数组。
示例 2:

输入: nums = [0,1,0]
输出: 2
说明: [0, 1] (或 [1, 0]) 是具有相同数量0和1的最长连续子数组。

一位大佬的代码链接,理解了一下思路:建立字典是为了统计从头开始到当下某个坐标的0与1数量的差值,开始坐标为-1,差值为0。如果是1,加1;如果是0,减1。每次结果与字典里的比较,如果存在相同的,说明两者之间的0与1的数量是相同的;不存在,加入字典。

class Solution:
    def findMaxLength(self, nums: List[int]) -> int:
        # 前缀和字典: key为1的数量和0的数量的差值,value为对应坐标
        hashmap = {0:-1}
        # 当前1的数量和0的数量的差值
        counter = ans = 0
        for i,num in enumerate(nums):
            # 每多一个1,差值+1
            if num:
                counter += 1
            # 每多一个0,差值-1
            else:
                counter -= 1
            # 如果存在1和0的数量差值相等的地方,那么说明后者到前者之前1和0的数量相等!
            if counter in hashmap:
                ans = max(ans, i - hashmap[counter])
            else:
                hashmap[counter] = i
        return ans


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

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:
给定 nums = [1,1,1,2,2,3],
函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。
你不需要考虑数组中超出新长度后面的元素。

示例 2:
给定 nums = [0,0,1,1,1,1,2,3,3],
函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。
你不需要考虑数组中超出新长度后面的元素。

说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。 // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。

思路一(从后往前遍历,使用pop)
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        for i in range(len(nums)-1,1,-1):
            if nums[i] == nums[i-2]:
                nums.pop(i)
        return len(nums)
思路二(不适用pop的情况下,用双指针、滑动窗口)
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        if len(nums) < 2:
            return len(nums)
        s = 2
        for i in range(2,len(nums)):
            if nums[i] !=nums[s-2]:
                nums[s] = nums[i]
                s += 1
        return s 

最多出现K次时的代码(K>1)
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        if len(nums) < k:
            return len(nums)
        s = k
        for i in range(k,len(nums)):
            if nums[i] !=nums[s-k]:
                nums[s] = nums[i]
                s += 1
        return s 

149. 直线上最多的点数

给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上。
思路:
首先如果点数小于 3 个,直接返回点数(因为肯定能组成直线)。
我们对所有点遍历,记录包含这个点在内的所有直线中,能组成的点数最多的直线的点数数量。
返回这些数量的最大值。
怎么遍历呢?
我们对一个点遍历的时候,再遍历所有点
维护两个变量
一个来记录和这个点相同的点(重复点)
一个来记录非重复点和这个点组成的各个直线以及它们拥有的点数
即使用哈希表,键为斜率,值是这个直线拥有的点数。这里使用 Counter 直接统计各个直线拥有的点数。
返回最多拥有点数的直线所拥有的点数与重复点之和。
可以参考分步代码
重复点的处理是难点。

from decimal import *

class Solution:
    def maxPoints(self, points: List[List[int]]) -> int:
        maxans = 0

        def K(i,j):
            return float('Inf') if i[1] - j[1] == 0 else Decimal(i[0] - j[0])/Decimal(i[1] - j[1])

        ## 两点确定一条直线
        if len(points) <= 2:
            return len(points)
        
        ## 遍历所有点
        for i in points:
            same = sum(1 for j in points if j == i)
            hashmap = Counter([K(i,j) for j in points if j != i])
            tempmax = hashmap.most_common(1)[0][1] if hashmap else 0
            maxans = max(same + tempmax, maxans)
        
        return maxans

994. 腐烂的橘子

在给定的网格中,每个单元格可以有以下三个值之一:

值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜橘子都会腐烂。

返回直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1。

输入:[[2,1,1],[1,1,0],[0,1,1]]
输出:4

示例 2:
输入:[[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个正向上。

示例 3:
输入:[[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。

思路:

这种需要一圈一圈往外传播的一般用BFS解,
先找到起始所有腐烂的橘子,
然后循环处理,把新腐烂的橘子加入下一次循环的队列中,
当下一次循环的队列为空时,说明不能继续腐烂了,
判断一下还有没有新鲜的橘子,如果有,就返回-1,否则返回分钟数

class Solution(object):
    def orangesRotting(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
        dx = [1, -1, 0, 0]
        dy = [0, 0, 1, -1]
        rotlist = list()
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == 2:
                    rotlist.append([i, j])
        minute = 0
        while(rotlist):
            newrotlist = list()
            for rotnode in rotlist:
                x0 = rotnode[0]
                y0 = rotnode[1]
                
                for k in range(4):
                    x = x0 + dx[k]
                    y = y0 + dy[k]
                    
                    if 0 <= x < len(grid) and 0 <= y < len(grid[0]) and grid[x][y] == 1:
                        grid[x][y] = 2
                        newrotlist.append([x,y])
            if not newrotlist:
                break
                
            rotlist = newrotlist[:]
            minute += 1
            
        for row in grid:
            for i in row:
                if i == 1:#还有新鲜的
                    return -1
        return minute
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. Two Sum 2. Add Two Numbers 3. Longest Substring Without Repeating Characters 4. Median of Two Sorted Arrays 5. Longest Palindromic Substring 6. ZigZag Conversion 7. Reverse Integer 8. String to Integer (atoi) 9. Palindrome Number 10. Regular Expression Matching 11. Container With Most Water 12. Integer to Roman 13. Roman to Integer 14. Longest Common Prefix 15. 3Sum 16. 3Sum Closest 17. Letter Combinations of a Phone Number 18. 4Sum 19. Remove Nth Node From End of List 20. Valid Parentheses 21. Merge Two Sorted Lists 22. Generate Parentheses 23. Swap Nodes in Pairs 24. Reverse Nodes in k-Group 25. Remove Duplicates from Sorted Array 26. Remove Element 27. Implement strStr() 28. Divide Two Integers 29. Substring with Concatenation of All Words 30. Next Permutation 31. Longest Valid Parentheses 32. Search in Rotated Sorted Array 33. Search for a Range 34. Find First and Last Position of Element in Sorted Array 35. Valid Sudoku 36. Sudoku Solver 37. Count and Say 38. Combination Sum 39. Combination Sum II 40. First Missing Positive 41. Trapping Rain Water 42. Jump Game 43. Merge Intervals 44. Insert Interval 45. Unique Paths 46. Minimum Path Sum 47. Climbing Stairs 48. Permutations 49. Permutations II 50. Rotate Image 51. Group Anagrams 52. Pow(x, n) 53. Maximum Subarray 54. Spiral Matrix 55. Jump Game II 56. Merge k Sorted Lists 57. Insertion Sort List 58. Sort List 59. Largest Rectangle in Histogram 60. Valid Number 61. Word Search 62. Minimum Window Substring 63. Unique Binary Search Trees 64. Unique Binary Search Trees II 65. Interleaving String 66. Maximum Product Subarray 67. Binary Tree Inorder Traversal 68. Binary Tree Preorder Traversal 69. Binary Tree Postorder Traversal 70. Flatten Binary Tree to Linked List 71. Construct Binary Tree from Preorder and Inorder Traversal 72. Construct Binary Tree from Inorder and Postorder Traversal 73. Binary Tree Level Order Traversal 74. Binary Tree Zigzag Level Order Traversal 75. Convert Sorted Array to Binary Search Tree 76. Convert Sorted List to Binary Search Tree 77. Recover Binary Search Tree 78. Sum Root to Leaf Numbers 79. Path Sum 80. Path Sum II 81. Binary Tree Maximum Path Sum 82. Populating Next Right Pointers in Each Node 83. Populating Next Right Pointers in Each Node II 84. Reverse Linked List 85. Reverse Linked List II 86. Partition List 87. Rotate List 88. Remove Duplicates from Sorted List 89. Remove Duplicates from Sorted List II 90. Intersection of Two Linked Lists 91. Linked List Cycle 92. Linked List Cycle II 93. Reorder List 94. Binary Tree Upside Down 95. Binary Tree Right Side View 96. Palindrome Linked List 97. Convert Binary Search Tree to Sorted Doubly Linked List 98. Lowest Common Ancestor of a Binary Tree 99. Lowest Common Ancestor of a Binary Search Tree 100. Binary Tree Level Order Traversal II
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值