leetcode刷题 373~
题目373题
查找和最小的k对数字
给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k。
定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2。
找到和最小的 k 对数字 (u1,v1), (u2,v2) ... (uk,vk)。
示例 1:
输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
输出: [1,2],[1,4],[1,6]
解释: 返回序列中的前 3 对数:
[1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]
思路
1.暴力法,取出所有数字排序
2.优先队列:
将数组1作为base,滑动数组2。每将一对作为结果输出时,将下一对加入队列中,若选择的这对位于数组2的开始,则将数组1滑动1位加入队列
实现
class Solution: def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]: """ 数组1作为base,滑动数组2 """ heap = [] def push(i, j): if i < len(nums1) and j < len(nums2): heapq.heappush(heap, [nums1[i] + nums2[j], i, j]) push(0,0) result = [] while heap and len(result) < k: pair, i, j = heapq.heappop(heap) result.append([nums1[i], nums2[j]]) push(i,j+1) if j == 0: push(i + 1, 0) return result
题目374题
猜数字大小
猜数字游戏的规则如下:
每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):
-1:我选出的数字比你猜的数字小 pick < num
1:我选出的数字比你猜的数字大 pick > num
0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num
思路
二分法
实现
class Solution: def guessNumber(self, n: int) -> int: left ,right = 1, n while left <= right: testcase = (left+right)//2 result = guess(testcase) if result == 0: return testcase elif result == 1: left = testcase+1 else: right = testcase-1
题目376题
摆动序列
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
例如, [1,7,4,9,2,5] 是一个摆动序列,因为差值 (6,-3,5,-7,3) 是正负交替出现的。相反, [1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。
思路
动态规划:维护一个增序列和一个减序列
实现
class Solution: def wiggleMaxLength(self, nums: List[int]) -> int: if len(nums) <2: return len(nums) up, down = 1, 1 for i in range(1, len(nums)): if nums[i] > nums[i-1]: up = down + 1 elif nums[i] < nums[i-1]: down = up+1 return max(up,down)
题目377题
组合总和IV
思路
1.递归:时间复杂度 O(target*n) 空间复杂度O(max(n,target))
2.动态规划O(n)
实现
1. class Solution: def combinationSum4(self, nums: List[int], target: int) -> int: result = 0 @functools.lru_cache(None) def combination(target): if target == 0: return 1 elif target < 0: return 0 ans = 0 for num in nums: ans += combination(target-num) return ans return combination(target) 2. class Solution: def combinationSum4(self, nums: List[int], target: int) -> int: dp = [0 for _ in range(target+1)] dp[0] = 1 for i in range(1,target+1): for num in nums: if i >= num: dp[i] += dp[i-num] return dp[target]
题目378题
有序矩阵中第K小的元素
思路
1.优先队列:与373题完全相同
2.二分法
实现
1. class Solution: def kthSmallest(self, matrix: List[List[int]], k: int) -> int: heap = [] n = len(matrix) def push(i, j): if i < n and j < n: heapq.heappush(heap, [matrix[i][j], i, j]) push(0,0) key = 1 while heap and key <= k: val, i ,j = heapq.heappop(heap) key += 1 push(i, j+1) if j == 0: push(i+1, 0) return val 2. class Solution: def kthSmallest(self, matrix: List[List[int]], k: int) -> int: n = len(matrix) def check(val): i, j = n-1, 0 num = 0 while i >=0 and j < n: if matrix[i][j] <= mid: j+=1 num += i + 1 else: i -= 1 return num >=k left, right = matrix[0][0], matrix[n-1][n-1] while left < right: mid = left + (right-left)//2 if check(mid): right = mid else: left = mid + 1 return left
题目380题
常数时间插入、删除、获取随机数
思路
数组+哈希表
实现
class RandomizedSet: def __init__(self): """ Initialize your data structure here. """ self.randomset = list() self.dic = dict() def insert(self, val: int) -> bool: """ Inserts a value to the set. Returns true if the set did not already contain the specified element. """ if val in self.dic: return False self.dic[val] = len(self.randomset) self.randomset.append(val) return True def remove(self, val: int) -> bool: """ Removes a value from the set. Returns true if the set contained the specified element. """ if val not in self.dic: return False index = self.dic[val] last = self.randomset[-1] self.randomset[index] = last self.dic[last] = index self.dic.pop(val) self.randomset.pop() return True def getRandom(self) -> int: """ Get a random element from the set. """ whole = len(self.randomset) index = random.randint(0,whole-1) return self.randomset[index]
题目382题
链表随机节点
思路
1.数组,将链表放入数组中,然后取数组的随机点,但是这样空间复杂度为O(n)
2.蓄水池抽样算法
实现
class Solution: def __init__(self, head: ListNode): """ @param head The linked list's head. Note that the head is guaranteed to be not null, so it contains at least one node. """ self.head = head def getRandom(self) -> int: """ Returns a random node's value. """ count = 0 head = self.head while head: count += 1 rand = random.randint(1,count) if rand == count: result = head.val head = head.next return result
题目367题
赎金信
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。
思路实现
class Solution: def canConstruct(self, ransomNote: str, magazine: str) -> bool: ransom = dict() for alpha in ransomNote: ransom[alpha] = ransom.get(alpha,0) + 1 for alpha in magazine: ransom[alpha] = ransom.get(alpha,0) - 1 for item in ransom: if ransom[item] > 0 : return False return True
题目384题
打乱数组
给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。
实现 Solution class:
Solution(int[] nums) 使用整数数组 nums 初始化对象
int[] reset() 重设数组到它的初始状态并返回
int[] shuffle() 返回数组随机打乱后的结果
思路实现
class Solution: def __init__(self, nums: List[int]): self.nums = nums self.original = list(nums) def reset(self) -> List[int]: """ Resets the array to its original configuration and return it. """ self.nums = self.original self.original = list(self.original) return self.nums def shuffle(self) -> List[int]: """ Returns a random shuffling of the array. """ count = len(self.nums) for i in range(count): rand1 = random.randint(0,count-1) self.nums[rand1], self.nums[i] = self.nums[i], self.nums[rand1] return self.nums
题目385题
迷你语法分析器
给定一个用字符串表示的整数的嵌套列表,实现一个解析它的语法分析器。
列表中的每个元素只可能是整数或整数嵌套列表
提示:你可以假定这些字符串都是格式良好的:
字符串非空
字符串不包含空格
字符串只包含数字0-9、[、-、,、]
思路
1.栈,遇见"[",则建立NestedInteger对象,并入栈,遇见","or"]",则添加数据,遇见"]"出栈并添加进入栈顶元素队列中
2.递归
实现
1. class Solution: def deserialize(self, s: str) -> NestedInteger: if s[0] != "[": return NestedInteger(int(s)) num, sign,is_num = 0 ,1, False stack = [] for i in s: if i.isdigit(): num = int(i) + num*10 is_num = True elif i == "-": sign = -1 elif i == "[": stack.append(NestedInteger()) elif i == "," or i == "]" : if is_num: cur = stack.pop() cur.add(NestedInteger(sign*num)) stack.append(cur) num, sign,is_num = 0 ,1, False if i == "]" and len(stack) > 1: cur = stack.pop() stack[-1].add(cur) return stack[0] 2. class Solution: def deserialize(self, s: str) -> NestedInteger: if s[0] != "[": return NestedInteger(int(s)) self.idx = 0 self.n = len(s) self.s = s return self.__deserialize() def __deserialize(self) -> NestedInteger: nested = NestedInteger() num, sign = 0, 1 while self.idx < self.n: self.idx += 1 if self.s[self.idx] == ",": continue elif self.s[self.idx] == "[": nested.add(self.__deserialize()) elif self.s[self.idx] == "]": return nested elif self.s[self.idx] == "-": sign = -1 else: num = num*10 + int(self.s[self.idx]) if self.s[self.idx+1] == "," or self.s[self.idx+1] == "]": nested.add(NestedInteger(sign*num)) num,sign = 0, 1
题目386题
字典序排数
给定一个整数 n, 返回从 1 到 n 的字典顺序。
例如,
给定 n =1 3,返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。
请尽可能的优化算法的时间复杂度和空间复杂度。 输入的数据 n 小于等于 5,000,000。
思路
1.动态规划和栈:
有三种情况:
当前数等于上一个数乘以10,上一个数入栈;当前数等于上一个数+1;当前数等于栈顶数+1
2.深度优先遍历
实现
class Solution: def lexicalOrder(self, n: int) -> List[int]: dp = [1 for _ in range(n+1)] stack = [0] for i in range(1,n): if dp[i] *10 <= n: dp[i+1] = dp[i]*10 stack.append(dp[i]) elif dp[i] + 1 < (stack[-1]+1)*10 and dp[i]+1 <= n: dp[i+1] = dp[i] + 1 else: while stack: sigh = stack.pop() if sigh + 1 < (stack[-1]+1)*10: dp[i+1] = sigh + 1 break return dp[1:]
题目387题
字符串中的第一个唯一字符
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
思路实现
class Solution: def firstUniqChar(self, s: str) -> int: result = [-1 for _ in range(26)] for i in range(len(s)): idx = ord(s[i]) - 97 if result[idx] == -1: result[idx] = i elif result[idx] >= 0: result[idx] = -2 res = len(s) for i in result: if i >= 0: res = min(i,res) return res if res < len(s) else -1
题目388题
文件的最长绝对路径
思路实现
class Solution: def lengthLongestPath(self, input: str) -> int: input = input.split("\n") dirindex = [] result = [] res = [0] def read(index): s = input[index] cur = s.count("\t") filelen = len(s) - cur # 寻找上级目录 last = cur - 1 lastlen = 0 if last >= 0: for i in range(len(dirindex)-1,-1,-1): if dirindex[i] == last: lastlen = result[i] + 1 break dirindex.append(cur) result.append(filelen+lastlen) if "." in s: res.append(filelen+lastlen) for i in range(len(input)): read(i) return max(res)
题目389题
找不同
给定两个字符串 s 和 t,它们只包含小写字母。
字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。
请找出在 t 中被添加的字母。
思路
字符串的ascii码之和 的差就是多出的字符
实现
class Solution: def findTheDifference(self, s: str, t: str) -> str: return chr(sum(map(ord, t)) - sum(map(ord, s)))
题目390题
消除游戏
给定一个从1 到 n 排序的整数列表。
首先,从左到右,从第一个数字开始,每隔一个数字进行删除,直到列表的末尾。
第二步,在剩下的数字中,从右到左,从倒数第一个数字开始,每隔一个数字进行删除,直到列表开头。
我们不断重复这两步,从左到右和从右到左交替进行,直到只剩下一个数字。
返回长度为 n 的列表中,最后剩下的数字。
思路
递归:
f(2k)=2(k+1−f(k))
实现
class Solution: def lastRemaining(self, n: int) -> int: return 1 if n==1 else 2*(n//2 + 1- self.lastRemaining(n//2))
题目392题
判断子序列
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
思路
贪心算法:从前往后匹配,可以发现每次贪心地匹配靠前的字符是最优决策。
实现
class Solution: def isSubsequence(self, s: str, t: str) -> bool: indx = 0 l = len(s) if not s: return True for i in t: if i == s[indx]: indx += 1 if indx == l: return True return False
题目393题
UTF-8编码验证
UTF-8 中的一个字符可能的长度为 1 到 4 字节,遵循以下的规则:
对于 1 字节的字符,字节的第一位设为0,后面7位为这个符号的unicode码。
对于 n 字节的字符 (n > 1),第一个字节的前 n 位都设为1,第 n+1 位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
思路实现
class Solution: def validUtf8(self, data: List[int]) -> bool: check = 0 for num in data: if num == 255: return False bin_num = '{:08b}'.format(num) zero = bin_num.index('0') if check == 0: if zero == 0: continue check += zero if check == 1 or check >4: return False else: if zero != 1: return False check -= 1 return check == 0
题目394题
字符串解码
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
思路
栈实现
实现
class Solution: def decodeString(self, s: str) -> str: num = 0 substring = "" num_stack = [] string_stack = [] result = "" for index in range(len(s)): i = s[index] if i.isdigit(): num = num*10 + int(i) elif i.isalpha(): string_stack.append(i) num_stack.append(1) if i == "[": num_stack.append(num) string_stack.append("") num = 0 elif i == "]": temp = "" while string_stack: if string_stack[-1] != "": temp = num_stack.pop()*string_stack.pop()+temp else: temp = num_stack.pop()*(string_stack.pop()+temp) break string_stack.append(temp) num_stack.append(1) if index == len(s)-1: for string in string_stack: result += string return result
题目395题
至少有k个重复字符的最长子串
找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不少于 k 。输出 T 的长度。
思路
将次数不足k的字符做为分隔符进行分割,对分割后的子串t递归调用函数,返回满足题目要求的最长子串长度
实现
class Solution: def longestSubstring(self, s: str, k: int) -> int: if len(s) < k: return 0 for alpha in set(s): if s.count(alpha) < k: return max(self.longestSubstring(sub, k) for sub in s.split(alpha)) return len(s)