leetcode刷题 396~

题目396题

旋转函数

给定一个长度为 n 的整数数组 A 。

假设 Bk 是数组 A 顺时针旋转 k 个位置后的数组,我们定义 A 的“旋转函数” F 为:

F(k) = 0 * Bk[0] + 1 * Bk[1] + ... + (n-1) * Bk[n-1]。

计算F(0), F(1), ..., F(n-1)中的最大值。

思路实现

class Solution:
    def maxRotateFunction(self, A: List[int]) -> int:
        if not A:
            return 0
        s,f0, l = 0, 0, len(A)
        for i in range(l):
            f0 += i * A[i]
            s += A[i]
        result = float("-inf")
        for i in range(l-1, -1, -1):
            f0 = f0 - l*A[i] + s
            result = max(result, f0)
        return result

题目397题

整数替换

思路

1.动态规划:居然超时了

2.记忆化递归:

  • @lru_cache(None)Python标准库,用于缓存

实现

1.
class Solution:
    def integerReplacement(self, n: int) -> int:
        if n == 1:
            return 0
        dp = [0 for _ in range(n+4)]
        dp[1],dp[2] = 0,1
        i = 4
        while dp[n] == 0:
            if i % 2 == 0:
                dp[i] = dp[i//2] + 1
                i -= 1
            elif i % 2 == 1:
                dp[i] = min(dp[i+1],dp[i-1]) + 1
                i += 3
        return dp[n]
2.
class Solution:
    def integerReplacement(self, n: int) -> int:
        @lru_cache(None)
        def dfs(n):
            if n==1:
                return 0

            ans=0
            if n&1:
                ans+=1+min(dfs(n+1),dfs(n-1))
            else:
                ans+=1+dfs(n//2)
            return ans
        
        return dfs(n)

题目398题

随机数索引

思路

1.字典:在初始化中建立字典,键为元素的值,值为元素索引组成的数组

2.蓄水池抽样

实现

class Solution:

    def __init__(self, nums: List[int]):
        self.dic =dict()
        for idx in range(len(nums)):
            self.dic.setdefault(nums[idx], []).append(idx)


    def pick(self, target: int) -> int:
        temp = self.dic[target]
        ran = random.randint(0,len(temp)-1)
        return temp[ran]
2.
class Solution:

    def __init__(self, nums: List[int]):
        self.nums = nums


    def pick(self, target: int) -> int:
        count = 0
        for idx in range(len(self.nums)):
            if self.nums[idx] == target:
                if random.randint(0,count) == 0:
                    result = idx
                count += 1
        return result

题目399题

除法求值

给出方程式 A / B = k, 其中 A 和 B 均为用字符串表示的变量, k 是一个浮点型数字。根据已知方程式求解问题,并返回计算结果。如果结果不存在,则返回 -1.0。

输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。

思路

深度优先遍历:先构造图,然后深度优先遍历

实现

class Solution:
    def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]:
        graph = {}
        for (x, y), v in zip(equations, values):
            if x in graph:
                graph[x][y] = v
            else:
                graph[x] = {y: v}
            if y in graph:
                graph[y][x] = 1/v
            else:
                graph[y] = {x: 1/v}
        def dfs(qs, qt)->int:
            if qs not in graph:
                return -1
            if qs == qt:
                return 1
            for node in graph[qs].keys():
                if node == qt:
                    return graph[qs][node]
                elif node not in visited:
                    visited.add(node)
                    value = dfs(node,qt)
                    if value != -1:
                        return graph[qs][node]*value
            return -1
        result = []
        for qs, qt in queries:
            visited = set()
            result.append(dfs(qs, qt))
        return result

题目400题

第N个数字

在无限的整数序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...中找到第 个数字。

思路

首先确定这个数的长度,根据长度来确实结束时的数的大小,然后判断是这个数字的第几位,最后返回结果

实现

class Solution:
    def findNthDigit(self, n: int) -> int:
        wei= 1
        index = wei * 9 * (10**(wei-1))
        while n > index:
            n -= index
            wei += 1
            index = wei * 9 * (10**(wei-1))
        num = (10**(wei-1)) + (n-1)//wei
        remain = (n-1)%wei
        numstr = str(num)
        return numstr[remain]

题目401题

二进制手表

二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)。每个 LED 代表一个 0 或 1,最低位在右侧。

示例:

输入: n = 1
返回: ["1:00", "2:00", "4:00", "8:00", "0:01", "0:02", "0:04", "0:08", "0:16", "0:32"]

思路

分别计算小时和分钟

实现

class Solution:
    def readBinaryWatch(self, num: int) -> List[str]:
        hour_result = []
        min_result = []
        def dfs(wei,num,res,sigh):
            if wei == 0 and num ==0:
                if sigh == True:
                    if res < 12:
                        hour_result.append(res)
                else:
                    if res <60:
                        min_result.append(res)
            elif wei <= 0:
                return 0
            for i in range(2):
                if i == 0:
                    dfs(wei-1,num,res,sigh)
                else:
                    dfs(wei-1,num-1,res+2**(wei-1),sigh)
        result = []
        for hour in range(num+1):
            hour_result = []
            min_result = []
            dfs(4,hour,0,True)
            dfs(6,num-hour,0,False)
            for i in hour_result:
                for j in min_result:
                    temp = str(i) + ":"
                    temp += str(j) if j>=10 else "0"+str(j)
                    result.append(temp)
        return result

题目402题

移掉K位数字

给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。

注意:

num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。

思路

给定一个数字序列 [D1D2D3…Dn] ,如果数字 D2 < D1,则我们应该删除左邻居D1,以获得最小结果。

实现

class Solution:
    def removeKdigits(self, num: str, k: int) -> str:
        result = []
        for i in num:
            while result and k and result[-1] > i:
                result.pop()
                k -= 1
            result.append(i)
        result = result[:-k] if k else result
        return "".join(result).lstrip('0') or "0"

题目404题

左叶子之和

计算给定二叉树的所有左叶子之和。

思路实现

class Solution:
    def sumOfLeftLeaves(self, root: TreeNode) -> int:
        
        def sumofleavse(node, sigh):
            val = 0
            if not node:
                return val
            if node.left:
                val += sumofleavse(node.left, True)
            if node.right:
                val += sumofleavse(node.right, False)
            if not node.left and not node.right and sigh:
                val += node.val
            return val

        return sumofleavse(root,False)

题目405题

数字转换为十六进制

给定一个整数,编写一个算法将这个数转换为十六进制数。对于负整数,我们通常使用 补码运算 方法。

思路

主要是理解补码:

num = (abs(num) ^ ((2 ** 32) - 1)) + 1

实现

class Solution:
    def toHex(self, num: int) -> str:
        hexnum = "0123456789abcdef"
        def get(num):
            result = ""
            while num != 0:
                i = num % 16
                result = hexnum[i] + result
                num = num // 16
            return result
        if num < 0:
            num = (abs(num) ^ ((2 ** 32) - 1)) + 1
        elif num ==0:
            return "0"
        return get(num)

题目406题

根据身高重建队列

假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。

注意:
总人数少于1100人。

示例

输入:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]

输出:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]

思路

没有做出来,查看解答后发现是利用的贪心算法,利用矮的人相对于高的人是看不见的:因为k的值是前面比自己高或等高的人的个数。先处理高的人,满足k的条件后,再处理矮的人是不会破坏这个条件的。

算法:

  • 排序:
    • 按高度降序排列。
    • 在同一高度的人中,按 k 值的升序排列。
  • 逐个地把它们放在输出队列中,索引等于它们的 k 值。
  • 返回输出队列

实现

class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        people = sorted(people, key = lambda x: (-x[0], x[1]))
        result =[]
        for i in people:
            result.insert(i[1],i)
        return result

题目395题

最长回文串

给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。

在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。

思路实现

class Solution:
    def longestPalindrome(self, s: str) -> int:
        dic = dict()
        for i in s:
            dic[i] = dic.get(i,0) + 1
        result,sign = 0, 0
        for i in dic:
            num = dic[i]//2
            if num >= 1:
                result += num*2
            if dic[i]%2 == 1:
                sign = 1
        return result+sign

题目412题

FizzBuzz

写一个程序,输出从 1 到 n 数字的字符串表示。

1. 如果 n 是3的倍数,输出“Fizz”;

2. 如果 n 是5的倍数,输出“Buzz”;

3.如果 n 同时是3和5的倍数,输出 “FizzBuzz”。

思路实现

class Solution:
    def fizzBuzz(self, n: int) -> List[str]:
        result = ["" for _ in range(n)]
        for i in range(n):
            temp = i+1
            if temp%3 == 0:
                result[i] += "Fizz"
            if temp%5 == 0:
                result[i] += "Buzz"
            if result[i] == "": 
                result[i] += str(temp)
        return result

题目414题

第三大的数

思路实现

class Solution:
    def thirdMax(self, nums: List[int]) -> int:
        first, second, third = float("-inf"), float("-inf"),float("-inf")
        for num in nums:
            if num > first:
                third,second = second,first
                first = num
            elif num == first:
                continue
            elif num > second:
                third = second
                second = num
            elif num == second:
                continue
            elif num > third:
                third = num
        if third != float("-inf"):
            return third
        else:
            return first

题目395题

字符串相加

思路实现

class Solution:
    def addStrings(self, num1: str, num2: str) -> str:
        index1, index2, add = len(num1)-1, len(num2)-1, 0
        result = ""
        while index1 >= 0 or index2 >=0 or add != 0:
            x = int(num1[index1]) if index1 >= 0 else 0
            y = int(num2[index2]) if index2 >= 0 else 0
            temp = x + y + add
            result = str(temp%10) + result
            add = temp//10
            index1 -= 1
            index2 -= 1
        return result

题目417题

太平洋大西洋水流问题

给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。

规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。

请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。

思路

深度优先遍历:最开始的时候期望正向流动来解决问题,但是遇到了许多问题:1.从不同的位置去访问同一个位置可能结果不同2.无法控制是否访问过(如果访问过就不再访问会漏解)

因此只能使用反向流动的方式来解决问题。以太平洋为例,从太平洋的边界向内遍历(按题目要求需要大于等于高度),如果能够遍历到说明在太平洋的界内;大西洋同理。大西洋和太平洋的交集就是最后的结果。

实现

class Solution:
    def pacificAtlantic(self, matrix: List[List[int]]) -> List[List[int]]:
        if not matrix or len(matrix) == 0:
            return []
        row, col = len(matrix), len(matrix[0])
        visied = [[0 for _ in range(col)] for _ in range(row)]
        a = [[0 for _ in range(col)] for _ in range(row)]
        p = [[0 for _ in range(col)] for _ in range(row)]
        move = [(0,1),(0,-1),(1,0),(-1,0)]
        result  = list()
        def dfs(i, j,temp):
            temp[i][j] = 1
            for x, y in move:
                ni,nj = i + x, j+y
                if 0<= ni < row and 0<= nj < col and matrix[i][j] <= matrix[ni][nj] and temp[ni][nj] != 1:
                    dfs(ni,nj,temp)

        for i in range(col):
            dfs(0, i, p)
            dfs(row-1, i, a)
        for i in range(row):
            dfs(i, 0 , p)
            dfs(i, col-1, a)
        for i in range(row):
            for j in range(col):
                if a[i][j] * p[i][j]:
                    result.append([i,j])
        return result

题目416题

分割等和子集

给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

注意:

每个数组中的元素不会超过 100
数组的大小不会超过 200
示例 1:

输入: [1, 5, 11, 5]

输出: true

解释: 数组可以分割成 [1, 5, 5] 和 [11].

思路

动态规划:背包问题,详细见背包问题九讲。

实现

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        total = sum(nums)
        if total%2 !=0:
            return False
        half = total//2
        dp = [[False for _ in range(half+1)] for _ in range(len(nums))]
        for i in range(len(nums)):
            for j in range(0,half+1):
                if nums[i] == j:
                    dp[i][j] = True
                    continue
                if nums[i] < j:
                    dp[i][j] = dp[i-1][j] or dp[i-1][j-nums[i]]
        return dp[-1][half] 
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        total = sum(nums)
        if total%2 !=0:
            return False
        half = total//2
        dp = [False for _ in range(half+1)]
        for i in range(len(nums)):
            for j in range(half,-1,-1):
                if nums[i] == j:
                    dp[j] = True
                    continue
                if nums[i] < j:
                    dp[j] = dp[j] or dp[j-nums[i]]
            print(dp)
        return dp[half]

题目419题

甲板上的战舰

思路

1.深度优先遍历

2.在进阶中要求扫描一次,且空间复杂度为O(n),因此只计算战舰头,若遇到x,其左边或者上面有x,则不计算

实现

class Solution:
    def countBattleships(self, board: List[List[str]]) -> int:
        count = 0
        row, col = len(board), len(board[0])
        def dfs(i,j):
            if board[i][j] == ".":
                return
            elif board[i][j] == "!":
                return
            elif board[i][j] == "X":
                board[i][j] = "!"
                if 0<= i+1 < row and 0<= j < col and board[i+1][j] == "X":
                    dfs(i+1,j)
                elif 0<= i < row and 0<= j+1 < col and board[i][j+1] == "X":
                    dfs(i,j+1)
                else:
                    nonlocal count
                    count += 1
        for i in range(row):
            for j in range(col):
                dfs(i,j)
        return count
class Solution:
    def countBattleships(self, board: List[List[str]]) -> int:
        count = 0
        row, col = len(board), len(board[0])
        for i in range(row):
            for j in range(col):
                if board[i][j] == ".":
                    continue
                if i>0 and board[i-1][j] == "X":
                    continue
                if j>0 and board[i][j-1] == "X":
                    continue
                count += 1
        return count

 

posted @ 2020-11-09 11:15  maoguai  阅读(110)  评论(0编辑  收藏  举报