2021-5

227. 基本计算器 II(中等)

实现一个基本的计算器来计算一个简单的字符串表达式的值。

字符串表达式仅包含非负整数,+, - ,*/ 四种运算符和空格  。 整数除法仅保留整数部分。

示例 1:

输入: "3+2*2"

输出: 7

示例 2:

输入: " 3/2 "

输出: 1

示例 3:

输入: " 3+5 / 2 "

输出: 5

说明:

  • 你可以假设所给定的表达式都是有效的。
  • 不要使用内置的库函数 eval

方法:栈

class Solution:

    def calculate(self, s: str) -> int:

        stack = []

        num = 0

        sign = '+'

        for i in range(len(s)):

            if s[i].isdigit():

                num = num*10+int(s[i])

            if s[i] in '+-*/' or i==len(s)-1:

                if sign == '+':

                    stack.append(num)

                elif sign == '-':

                    stack.append(-num)

                elif sign =='*':

                    stack.append(stack.pop()*num)

                else:

                    stack.append(int(stack.pop()/num))

                num = 0

                sign = s[i]

        return sum(stack)

1002. 查找常用字符(简单)

给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。

你可以按任意顺序返回答案。

 

示例 1

输入:["bella","label","roller"]

输出:["e","l","l"]

示例 2

输入:["cool","lock","cook"]

输出:["c","o"]

 

提示:

1 <= A.length <= 100

1 <= A[i].length <= 100

A[i][j] 是小写字母

方法:计数

class Solution:

    def commonChars(self, A: List[str]) -> List[str]:

        minfreq = [float("inf")]*26

        for word in A:

            freq = [0]*26

            for ch in word:

                freq[ord(ch)-ord("a")] += 1

            for i in range(26):

                minfreq[i] = min(minfreq[i], freq[i])

        ans = list()

        for i in range(26):

            ans.extend([chr(i+ord("a"))]*minfreq[i])

        return ans

43. 字符串相乘(中等)

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

示例 1:

输入: num1 = "2", num2 = "3"

输出: "6"

示例 2:

输入: num1 = "123", num2 = "456"

输出: "56088"

说明:

  1. num1 和 num2 的长度小于110。
  2. num1 和 num2 只包含数字 0-9
  3. num1 和 num2 均不以零开头,除非是数字 0 本身。
  4. 不能使用任何标准库的大数类型(比如 BigInteger直接将输入转换为整数来处理

方法1:做加法

如果 num1num2之一是 0,则直接将 0作为结果返回即可。

 

如果num1 num2都不是 0,则可以通过模拟「竖式乘法」的方法计算乘积。从右往左遍历乘数,将乘数的每一位与被乘数相乘得到对应的结果,再将每次得到的结果累加。这道题中,被乘数是 num1,乘数是num2

需要注意的是,num2除了最低位以外,其余的每一位的运算结果都需要补 0

 

复杂度分析

时间复杂度:O(mn+n^2),其中 m n 分别是num1 num2的长度。需要从右往左遍历 num2,对于 num2的每一位,都需要和 num1的每一位计算乘积,因此计算乘积的总次数是 mn。字符串相加操作共有 n 次,相加的字符串长度最长为 m+n,因此字符串相加的时间复杂度是 O(mn+n^2)。总时间复杂度是 O(mn+n^2)

空间复杂度:O(m+n),其中 m n 分别是 num1 num2的长度。空间复杂度取决于存储中间状态的字符串,由于乘积的最大长度为 m+n,因此存储中间状态的字符串的长度不会超过 m+n

class Solution:

    def multiply(self, num1: str, num2: str) -> str:

        if num1 == '0' or num2 == '0':

            return '0'

        m, n = len(num1), len(num2)

        res = '0'

        for i in range(n-1-1-1):

            y = int(num2[i])

            add = 0

            cur = ['0']*(n-i-1)

            for j in range(m-1-1-1):

                product = int(num1[j])*y + add

                cur.append(str(product%10))

                add = product // 10

            if add > 0:

                cur.append(str(add))

            cur = ''.join(cur[::-1])

            res = self.addString(res, cur)

        return res 

    def addString(self, num1: str, num2: str) -> str:

        i, j = len(num1)-1len(num2)-1

        add = 0

        res = []

        while i >= 0 or j >= 0 or add != 0:

            x = int(num1[i]) if i >= 0 else 0

            y = int(num2[j]) if j >= 0 else 0

            result = x + y + add

            res.append(str(result%10))

            add = result // 10

            i -= 1

            j -= 1

        return ''.join(res[::-1])

方法2:

17. 电话号码的字母组合(中等)

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

https://assets.leetcode-cn.com/aliyun-lc-upload/original_images/17_telephone_keypad.png

示例:

输入:"23"

输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

方法1:回溯

首先使用哈希表存储每个数字对应的所有可能的字母,然后进行回溯操作。

每次取电话号码的一位数字,从哈希表中获得该数字对应的所有可能的字母,并将其中的一个字母插入到已有的字母排列后面,然后继续处理电话号码的后一位数字,直到处理完电话号码中的所有数字,即得到一个完整的字母排列。然后进行回退操作,遍历其余的字母排列。

 

回溯算法用于寻找所有的可行解,如果发现一个解不可行,则会舍弃不可行的解。在这道题中,由于每个数字对应的每个字母都可能进入字母组合,因此不存在不可行的解,直接穷举所有的解即可。

 

 

 

 

 

……

 

class Solution:

    def letterCombinations(self, digits: str) -> List[str]:

        if not digits:

            return list()

        phoneMap = {

            "2""abc",

            "3""def",

            "4""ghi",

            "5""jkl",

            "6""mno",

            "7""pqrs",

            "8""tuv",

            "9""wxyz"

        }

 

        def backtrace(index):

            if index == len(digits):

                res.append("".join(temp))

            else:

                digit = digits[index]

                for ch in phoneMap[digit]:

                    temp.append(ch)

                    backtrace(index+1)

                    temp.pop()

        

        res = []

        temp = []

        backtrace(0)

        return res

方法2:回溯:itertools.product()

from itertools import product

 

class Solution:

    def letterCombinations(self, digits: str) -> List[str]:

        if not digits:

            return list()

        phoneMap = {

            '2''abc',

            '3''def',

            '4''ghi',

            '5''jkl',

            '6''mno',

            '7''pqrs',

            '8''tuv',

            '9''wxyz'

        }

        groups = [phoneMap[digit] for digit in digits]

        return [''.join(item) for item in product(*groups)]

824. 山羊拉丁文(简单)

给定一个由空格分割单词的句子 S。每个单词只包含大写或小写字母。

我们要将句子转换为 “Goat Latin”(一种类似于 猪拉丁文 - Pig Latin 的虚构语言)。

山羊拉丁文的规则如下:

  • 如果单词以元音开头(a, e, i, o, u),在单词后添加"ma"
    例如,单词"apple"变为"applema"
  • 如果单词以辅音字母开头(即非元音字母),移除第一个字符并将它放到末尾,之后再添加"ma"
    例如,单词"goat"变为"oatgma"
  • 根据单词在句子中的索引,在单词最后添加与索引相同数量的字母'a',索引从1开始。
    例如,在第一个单词后添加"a",在第二个单词后添加"aa",以此类推。

返回将 S 转换为山羊拉丁文后的句子。

示例 1:

输入: "I speak Goat Latin"

输出: "Imaa peaksmaaa oatGmaaaa atinLmaaaaa"

示例 2:

输入: "The quick brown fox jumped over the lazy dog"

输出: "heTmaa uickqmaaa rownbmaaaa oxfmaaaaa umpedjmaaaaaa overmaaaaaaa hetmaaaaaaaa azylmaaaaaaaaa ogdmaaaaaaaaaa"

说明:

  • S 中仅包含大小写字母和空格。单词间有且仅有一个空格。
  • 1 <= S.length <= 150

class Solution:

    def convert(self, word):

        if word[0not in 'aeiouAEIOU':

            word = word[1:] + word[:1]

        return word + 'ma'

 

    def toGoatLatin(self, S: str) -> str:

        return " ".join(self.convert(word) + 'a' * i  for i, word in enumerate(S.split(), 1))

 

二分查找

贪心法

1231

376

452. 用最少数量的箭引爆气球(中等)

在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以y坐标并不重要,因此只要知道开始和结束的x坐标就足够了。开始坐标总是小于结束坐标。平面内最多存在104个气球。

一支弓箭可以沿着x轴从不同点完全垂直地射出。在坐标x处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足  xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。

Example:

输入:

[[10,16], [2,8], [1,6], [7,12]]

输出:

2

解释:

对于该样例,我们可以在x = 6(射爆[2,8],[1,6]两个气球)和 x = 11(射爆另外两个气球)。

方法:贪心法

跟踪气球的结束坐标:

(1)若下个气球开始坐标在当前气球的结束坐标前,则我们可以用一支箭一起引爆。

(2)若下个气球的开始坐标在当前气球的结束坐标后,则我们必须增加箭的数量,并跟踪下个气球的结束坐标。

算法:

(1)根据 x_end 将气球进行排序。

(2)初始化 first_end 为第一个气球结束的坐标 points[0][1]。

初始化箭的数量 arrows = 1。

(3)遍历所有的气球:

如果气球的开始坐标大于 first_end:则增加箭的数量,

并将 first_end 设置为当前气球的 x_end。

class Solution:

    def findMinArrowShots(self, points: List[List[int]]) -> int:

        if not points:

            return 0

        points.sort(key = lambda x: x[1])

        res = 1

        first_end = points[0][1]

        for x_start, x_end in points:

            if first_end < x_start:

                res += 1

                first_end = x_end

        return res

392. 判断子序列(简单)

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

示例 1:
s = "abc"t = "ahbgdc"

返回 true.

示例 2:
s = "axc"t = "ahbgdc"

返回 false.

解题思路:双指针

本题询问的是,s是否是 t的子序列,因此只要能找到任意一种 s 在 t 中出现的方式,即可认为 s 是 t 的子序列。

而当我们从前往后匹配,可以发现每次贪心地匹配靠前的字符是最优决策。

 

这样,我们初始化两个指针 i 和 j,分别指向 s 和 t 的初始位置。每次贪心地匹配,匹配成功则 i 和 j 同时右移,匹配 s 的下一个位置,匹配失败则 j 右移,i 不变,尝试用 t 的下一个字符匹配 s。

最终如果 i 移动到 s的末尾,就说明 s 是 t 的子序列。

class Solution:

    def isSubsequence(self, s: str, t: str) -> bool:

        n, m = len(s), len(t)

        i = j = 0

        while i < n and j < m:

            if s[i] == t[j]:

                i += 1

            j += 1

        return i == n

455. 分发饼干(简单)

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

注意:

你可以假设胃口值为正。
一个小朋友最多只能拥有一块饼干。

示例 1:

输入: [1,2,3], [1,1]

 

输出: 1

解释:

你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。

虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。

所以你应该输出1。

示例 2:

输入: [1,2], [1,2,3]

输出: 2

解释:

你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。

你拥有的饼干数量和尺寸都足以让所有孩子满足。

所以你应该输出2.

解题思路:贪心

先排序(从小到大,从大到小排序均可),然后利用贪心算法,对饼干进行遍历,如果饼干能满足小孩胃口,满足小孩的数量+1,直到饼干遍历完或者小孩都满足。

从大到小排序:

class Solution:

    def findContentChildren(self, g: List[int], s: List[int]) -> int:

        g = sorted(g, reverse=True)

        s = sorted(s, reverse=True)

        n, m = len(g), len(s)

        i, j, count = 000

        while i < n and j < m:

            if g[i] <= s[j]:

                j += 1

                count += 1

            i += 1

        return count

********************************************************

从小到大排序:

class Solution:

    def findContentChildren(self, g: List[int], s: List[int]) -> int:

        g = sorted(g)

        s = sorted(s)

        n, m = len(g), len(s)

        i, j, count = 000

        while i < n and j < m:

            if g[i] <= s[j]:

                i += 1

                count += 1

            j += 1

        return count2021-5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值