1. Two Sum
给定一个数组,找出数组两个元素相加为目标值,假定只有唯一解。原题
1 | Given nums = [2, 7, 11, 15], target = 9, |
1 | def two_sum(nums, target): |
15. 3Sum
找出3个数相加为0的所有组合。
方法一:固定一个数,再通过双指针找另外两个。
1 | def threeSum(self, nums: List[int]) -> List[List[int]]: |
18. 4Sum
找出4个数和为target的组合。
方法一:还是根据3sum的方法进行修改。
1 | def fourSum(self, nums: List[int], target: int) -> List[List[int]]: |
454. 4Sum II
在四个数组中每个各选出一个,使得它们所有的和为0。
1 | Input: |
方法一:和18题不同,这里不需要想3Sum之后怎么怎么样,因为3Sum的方法需要排序,而这里没法处理两个数组排序,双指针也比较麻烦了。换一个思路,拆成2个2Sum的子问题。
1 | def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int: |
1 | def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int: |
720. Longest Word in Dictionary
字典中的最长单词,找出一个列表中的一个单词,该单词的子单词也必须在字典中。相同长度的单词,返回字典序最前的一个。原题
1 | Input: |
方法一:Brute Force.
1 | def longestWord(self, words): |
方法二:trie. 暂且留坑。
748. Shortest Completing Word
最短的完整匹配单词。包含licensePlate
中的所有字母,大小写不敏感。假设答案一定存在。原题
1 | Input: licensePlate = "1s3 PSt", words = ["step", "steps", "stripe", "stepple"] |
方法一:先排序。
1 | def shortestCompletingWord(self, licensePlate: 'str', words: 'List[str]') -> 'str': |
1 | def shortestCompletingWord(self, licensePlate: 'str', words: 'List[str]') -> 'str': |
-
的操作时,涉及一些无关的key导致效率过低。
1 | def shortestCompletingWord(self, licensePlate: 'str', words: 'List[str]') -> 'str': |
811. Subdomain Visit Count
子域名访问量。给定一个三级或二级域名列表,统计所有三级、二级和顶级域名的访问量。原题
1 | Example 1: |
方法一:Solution中用了Counter,个人认为defaultdict.
1 | def subdomainVisits(self, cpdomains: 'List[str]') -> 'List[str]': |
884. Uncommon Words from Two Sentences
求两句话中的单词,在本句中出现一次,并不在另一句中的单词。也就是在两句中出现一次。原题
1 | Input: A = "this apple is sweet", B = "this apple is sour" |
方法一:Counter
1 | def uncommonFromSentences(self, A: 'str', B: 'str') -> 'List[str]': |
1010. Pairs of Songs With Total Durations Divisible by 60
和能被60整除的为一对,求有多少对。原题
1 | Input: [30,20,150,100,40] |
1 | def numPairsDivisibleBy60(self, time: List[int]) -> int: |
1138. Alphabet Board Path
小写字母排列的键盘,要打出目标字母需要移动的操作。原题
1 | Input: target = "leet" |
方法一:此题需要注意z,然后按照一个优先的顺序移动即可。另外使用字典可以快速定位坐标,而不用每个字符做比较
1 | def alphabetBoardPath(self, target: str) -> str: |
1072. Flip Columns For Maximum Number of Equal Rows
二维数组,翻转某几列可以最多使多少行内的元素都相同。原题
1 | Input: [[0,1],[1,1]] |
方法一:核心思想在于找到每行的模式,具有相同模式的行,最终可变成同样的数值。
1 | def maxEqualRowsAfterFlips(self, matrix: List[List[int]]) -> int: |
1 | def maxEqualRowsAfterFlips(self, matrix: List[List[int]]) -> int: |
1160. Find Words That Can Be Formed by Characters
找出能被目标字符串组成的子串长度和。原题
1 | def countCharacters(self, words: List[str], chars: str) -> int: |
525. Contiguous Array
找出二进制数组中拥有相等个数0和1的最长子串的长度。原题
1 | Input: [0,1] |
方法一:此题解法类似于买卖股票,维护一个count
如果是0减一,如果是1加一,那么当count值相等的时候,说明这个子串中有相等1和0。使用一个字典来记录每次count的最小索引。需要注意的是索引从1开始。
1 | def findMaxLength(self, nums: List[int]) -> int: |
560. Subarray Sum Equals K
子数组和为k的个数。原题
1 | Input:nums = [1,1,1], k = 2 |
方法一:累加一开始想到了,补0也想到了,没想到用哈希,而是用循环去迭代,这样时间超时了。
1 | def subarraySum(self, nums: List[int], k: int) -> int: |
1074. Number of Submatrices That Sum to Target
和为目标值的子矩阵个数。
1 | Input: matrix = [[0,1,0],[1,1,1],[0,1,0]], target = 0 |
方法一:560的升级版。需要先求出每行的前缀和。然后选定两个列(可以相同),以这两个列为宽度,高度逐渐递增,寻找这个宽度的子矩阵的和。
1 | def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int: |
1311. Get Watched Videos by Your Friends
找到你的level级别的朋友看的电影,按照频率字母排序。原题
1 | Input: watchedVideos = [["A","B"],["C"],["B","C"],["D"]], friends = [[1,2],[0,3],[0,3],[1,2]], id = 0, level = 1 |
1 | def watchedVideosByFriends(self, watchedVideos: List[List[str]], friends: List[List[int]], id: int, level: int) -> List[str]: |
388. Longest Absolute File Path
最长的绝对路径。原题
方法一:自己用栈实现的。
1 | def lengthLongestPath(self, input: str) -> int: |
1 | def lengthLongestPath(self, input: str) -> int: |
1224. Maximum Equal Frequency
给定一个数组,返回这个数组最长的前缀,前缀中刚好有删除一个元素使其它元素的频率相等。原题
1 | Input: nums = [2,2,1,1,5,3,3,5] |
方法一:Lee215的答案,一共分为两种情况,一种情况是将当前元素删除,那么前面的元素具有相同的频率。如果不删除当前的元素,那么这个元素出现了c次,我们用freq
来记录出现i次的有多少个数。那么删除的元素只能是出现c+1次或者1次,并且这个数只有一个。
1 | def maxEqualFreq(self, A: List[int]) -> int: |
957. Prison Cells After N Days
有8个监狱,如果两边的监狱是相同的,那么次日这个监狱会有人,否则为空。求N天之后的监狱原题
1 | Input: cells = [0,1,0,1,1,0,0,1], N = 7 |
方法一:看了提示用hash但是还是没想到,总共有8个监狱,首位肯定是0,那么还有6个,6个监狱一共有多少种情况呢,2**6,也就是说最多这些天形成一种循环。
1 | def prisonAfterNDays(self, cells: List[int], N: int) -> List[int]: |
方法二:Lee发现了规律,有三个情况一种是1,7,14的时候循环。那么,每14次进行一次循环。但是不能直接进行取余,因为当过了一天,才会进入14天循环中的一天,所以如果当N能被14整除时,并且首位不为0,那么实际上他需要进行变换,而不是直接返回。
1 | def prisonAfterNDays(self, cells: List[int], N: int) -> List[int]: |
1546. Maximum Number of Non-Overlapping Subarrays With Sum Equals Target
和为目标值的子数组最多有多少个,子数组不能重复。原题
1 | Input: nums = [1,1,1,1,1], target = 2 |
方法一:题目分类为dp。但我感觉更适合哈希,比赛的时候想到了一下TwoSum的思路,但是重置seen为空那步没想到。
1 | def maxNonOverlapping(self, nums: List[int], target: int) -> int: |
1577. Number of Ways Where Square of Number Is Equal to Product of Two Numbers
找到一个数组中两个元素乘积等于另一个数组的平方,求总共的个数。原题
1 | Input: nums1 = [7,7,8,3], nums2 = [1,2,9,7] |
方法一:比赛时想复杂了,但还是做出来了。比赛时想的是Counter原数组,根据平方找值。实际上通过combine方法可以反过来算简单。
1 | def numTriplets(self, nums1: List[int], nums2: List[int]) -> int: |
916. Word Subsets
给两个单词列表,返回A中满足这样条件的单词:B中的所有单词都是此单词的子集。原题
1 | Input: A = ["amazon","apple","facebook","google","leetcode"], B = ["e","oo"] |
方法一:Counter 比较简单。效率不咋高。
1 | def wordSubsets(self, A: List[str], B: List[str]) -> List[str]: |
1 | def wordSubsets(self, A: List[str], B: List[str]) -> List[str]: |
1 | def wordSubsets(self, A: List[str], B: List[str]) -> List[str]: |
974. Subarray Sums Divisible by K
连续的子数组的和能被K整除的个数。原题
1 | Input: A = [4,5,0,-2,-3,1], K = 5 |
方法一:这道题没有在规定时间内完成,此答案参考了排名第一的大佬,然后使用defaultdict
进行了改进。
这里有一个详细的解答。不过那里给出的答案没有这个简单,不过思路大体相同。
假设通过sum(i, j)
表示切片[i: j]的总和,如果sum(i, j)
能被K整除,则说明sum(0, j) - sum(0, i)
也能被K整除,即对sum(0, j) % K == sum(0, i) % K
。下面的解法使用一个字典记录了余数的个数。当余数第二次出现的时候,开始计数,但0的时候除外,因为整除了就产生结果了。
然后再看累加的方法以下文第3行log为例,mod又为4,这时它和之前余数为4的的数组都可以产生一个结果即[4, 5, 0] - [4] = [5, 0]
和[4 , 5, 0] - [4, 5] = [0]
所以要累加原来的和。
1 | def subarraysDivByK(self, A, K): |
1 | sum subarray [4] total is 4, mod is 4, ans is 0, defaultdict(<class 'int'>, {0: 1, 4: 1}) |
1590. Make Sum Divisible by P
删除最小的连续子数组,使得整个数组和能被P整除。
方法一:此题作为竞赛第三题,比二题简单,但是竞赛的时候没有做。首先可以用总和%p看余几,然后就是找到最小的子数组能让余数等于这个,就把这个删除,这一点很好想。剩下的和974一样。
1 | def minSubarray(self, nums: List[int], p: int) -> int: |
692. Top K Frequent Words
最高频的K个单词,相同频率,优先返回字符顺序优先。
1 | Input: ["i", "love", "leetcode", "i", "love", "coding"], k = 2 |
方法一:记录写法,nsmallest 也能接受key函数。
1 | def topKFrequent(self, words: List[str], k: int) -> List[str]: |
1399. Count Largest Group
以数字和为分组,求最大组的个数。原题
1 | Input: n = 13 |
方法一:Counter
1 | def countLargestGroup(self, n: int) -> int: |
方法二:标准库。statistics.multimode
返回一个可迭代对象中出现次数最多的元素。
1 | def countLargestGroup(self, n: int) -> int: |
1394. Find Lucky Integer in an Array
找到数组中数字和出现次数一致的最大的数。原题
1 | Input: arr = [2,2,3,4] |
1 | def findLucky(self, arr: List[int]) -> int: |
1128. Number of Equivalent Domino Pairs
相等的多米诺骨牌对数。原题
方法一:把牌翻转成一样的,然后组合。
1 | def numEquivDominoPairs(self, dominoes: List[List[int]]) -> int: |
1002. Find Common Characters
在给定的单词列表中找到公共字符。原题
1 | Input: ["bella","label","roller"] |
1 | def commonChars(self, A: List[str]) -> List[str]: |
697. Degree of an Array
degree这里表示数组最常见的元素的频率,然后在连续的子数组中寻找同样的degree,求最小子数组的长度。原题
1 | Input: [1, 2, 2, 3, 1] |
方法一:使用Counter 和index. 600ms有点慢。
1 | def findShortestSubArray(self, nums): |
1 | def findShortestSubArray(self, nums): |
1 | def findShortestSubArray(self, nums: 'List[int]') -> 'int': |
187. Repeated DNA Sequences
找出出现两次以上的DNA连续序列,序列长度为10。
1 | Input: s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT" |
1 | class Solution: |
方法二:此题有个位运算的标签,所以试了一下,将DNA序列编码为二进制的形式。
1 | def findRepeatedDnaSequences(self, s: str) -> List[str]: |
1658. Minimum Operations to Reduce X to Zero
给定一个数组和一个目标数x,每次可以将x-数组两边的某个数,最少需要多少步可以将x变为0。
1 | Input: nums = [1,1,4,2,3], x = 5 |
方法一:变长滑动窗口。比赛时没有做出来,想成BFS了,结果超时。这题和1423很像,那题是定长的滑动窗口,此题可以转化为,找到一个最长的窗口使得窗口值的和等于总和-x。1200ms.
1 | def minOperations(self, nums: List[int], x: int) -> int: |
i
表示从右边减去的数字,mp[x]
表示从左边减去的数字。
1 | def minOperations(self, nums: List[int], x: int) -> int: |
1711. Count Good Meals
给你一个整数数组 deliciousness ,其中 deliciousness[i] 是第 i 道餐品的美味程度,返回你可以用数组中的餐品做出的不同 大餐 的数量。结果需要对 109 + 7 取余。
1 | Input: deliciousness = [1,3,5,7,9] |
方法一:哈希。比赛时相出了两数之和的思想,但是想放到Counter中遍历,这样写非常麻烦,直接遍历原数组就好。1400ms
1 | def countPairs(self, dis: List[int]) -> int: |
方法二:使用Counter遍历,1176ms。
1 | def countPairs(self, dis: List[int]) -> int: |
2122. Recover the Original Array
恢复原始的数组,给你一个合并后的数组,由原数组每个元素-k和+k形成两个数组后合并。
1 | Input: nums = [2,10,6,4,8,12] |
方法一:竞赛时险过,有两个地方想复杂了,其实没必要用堆,本来复制数组就用了O(N)的复杂度。思路是先找2k
,然后判断这个是否可行。找的过程也是需要O(N)。
1 | def recoverArray(self, nums: List[int]) -> List[int]: |
2488. Count Subarrays With Median K
统计子数组中位数为k的个数。
给你一个长度为 n
的数组 nums
,该数组由从 1
到 n
的 不同 整数组成。另给你一个正整数 k
。
统计并返回 num
中的 中位数 等于 k
的非空子数组的数目
1 | 输入:nums = [3,2,1,4,5], k = 4 |
方法一:比赛时没有时间做,瞄了一眼以为用堆,结果不是。首先很重要得一个条件是,所有的数不同,那么能使中位数为K,一定会包含k,所以可以围绕k向两侧拓展。
对于一个合理的子数组,一定保证小于k的和大于k的相等(奇数),小于k的+1等于大于k的(偶数)。
用 l1
, s1
表示k左侧比k大,比k小的个数。l2
,s2
表示k右侧比k大,比k小的个数。
得出l1+l2=s1+s2
或者l1+l2=s1+s2+1
,推论出l1-s1=s2-l2
和l1-s1=s2-l2+1
。这样可以维护一个map来计数。注意,需要考虑没有左或者右的情况。
1 | def countSubarrays(self, nums: List[int], k: int) -> int: |