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:]
class Solution:
    def lexicalOrder(self, n: int) -> List[int]:
        result = []
        def dfs(num):
            if num >n:
                return
            result.append(num)
            for i in range(0,10):
                dfs(num*10 + i)
        for i in range(1,10):
            dfs(i)
        return result

题目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+1f(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 。输出 的长度。

思路

将次数不足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)

 

posted @ 2020-11-02 14:20  maoguai  阅读(228)  评论(0编辑  收藏  举报