LeetCode 算法系列:第 41 ~ 45题

目录

  1. 缺失的第一个正数
  2. 接雨水
  3. 字符串相乘
  4. 通配符匹配
  5. 跳跃游戏 II

41. 缺失的第一个正数

给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。

示例 1:

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

示例 2:

输入: [3,4,-1,1] 输出: 2

示例 3:

输入: [7,8,9,11,12] 输出: 1

思路:
将所有的数用map存起来,然后从1依次开始找没有出现在map中的最小的正整数

c++版

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        map<int,int>mp;
        int n = nums.size();
        for(int i=0;i<n;i++)
        {
            mp[nums[i]]++;
        }
        for(int i =1;i<=n;i++)
        {
            if(mp.count(i)==0)
            return i;
        }
        return n+1;
    }
};

python 代码

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        map<int, int> mp;
        int n = nums.size();
        for(int i = 0; i < n; i++)
            mp[nums[i]] = 1;
        for(int i = 1; i <= n; i++){
            if(mp.count(i) == 0)
                return i;
        }
        return n + 1;
    }
};

42. 接雨水

题目描述
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
在这里插入图片描述
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

思路

单调栈的应用
我们用栈保存每堵墙。 当遍历墙的高度的时候,如果当前高度小于栈顶的墙高度,说明这里会有积水,我们将墙的高度的下标入栈。
如果当前高度大于栈顶的墙的高度,说明之前的积水到这里停下,我们可以计算下有多少积水了。计算完,就把当前的墙继续入栈,作为新的积水的墙。
总体的原则就是,
1.当前高度小于等于栈顶高度,入栈,指针后移。
2.当前高度大于栈顶高度,出栈,计算出当前墙和栈顶的墙之间水的多少,然后计算当前的高度和新栈的高度的关系,重复第 2 步。 直到当前墙的高度不大于栈顶高度或者栈空,然后把当前墙入栈,指针后移。

c++代码

class Solution {
public:
    int trap(vector<int>& height) {
        stack<int>s;
        int n = height.size();
        int res = 0;
        for(int i =0;i<n;i++)
        {
            while(s.size()&&height[s.top()]<height[i])//计算存储的水量
            {
                int h = height[s.top()];
                s.pop();
                if(s.empty())break;
                int d = i-s.top()-1;
                h = min(height[s.top()],height[i])-h;
                res += h*d;
            }
            s.push(i);
        }
        return res;
    }
};

python代码

class Solution:
    def trap(self, height: List[int]) -> int:
        l = []
        res = 0
        n = len(height)
        for i in range(n):
            while len(l) != 0 and height[l[-1]] < height[i]:
                h = height[l[-1]]
                l.pop()
                if len(l) == 0:
                    break
                d = i - l[-1] - 1
                h = min(height[l[-1]], height[i]) - h
                res += d * h
            l.append(i)
        return res

43. 字符串相乘

题目描述

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

示例 1:

输入: num1 = “2”,
num2 = “3” 输出: “6”

示例 2:

输入: num1 = “123”, num2 = “456” 输出: “56088”

说明:

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

思路

高精度乘法问题

c++代码

class Solution {
public:
    string multiply(string num1, string num2) {
        int n = num1.size();
        int m = num2.size();
        vector<int>a,b,c(n+m);
        for(int i = n-1;i>=0;i--)
        {
            a.push_back(num1[i]-'0');
        }
        for(int j =m-1;j>=0;j--)
        {
            b.push_back(num2[j]-'0');
        }
        for(int i =0;i<n;i++)
        {
            for(int j =0;j<m;j++)
            {
                c[i+j] += a[i]*b[j];
                c[i+j+1]+=c[i+j]/10;
                c[i+j]=c[i+j]%10;
            }
        }
        int l =n+m-1;
        string s = "";
        while(l>0&&c[l]==0)l--;
        while(l>=0)s+=c[l]+'0',l--;
        return s;

    }
};

python代码

class Solution(object):
    def multiply(self, num1, num2):
        if num1 == "0" or num2 == "0":
            return "0"
        ans = "0"
        m, n = len(num1), len(num2)
        for i in range(n - 1, -1, -1):
            add = 0
            y = int(num2[i])
            curr = ["0"] * (n - i - 1)
            for j in range(m - 1, -1, -1):
                product = int(num1[j]) * y + add
                curr.append(str(product % 10))
                add = product // 10
            if add > 0:
                curr.append(str(add))
            curr = "".join(curr[::-1])
            ans = self.addStrings(ans, curr)   
        return ans
   
    def addStrings(self, num1, num2):
        i, j = len(num1) - 1, len(num2) - 1
        add = 0
        ans = list()
        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
            ans.append(str(result % 10))
            add = result // 10
            i -= 1
            j -= 1
        return "".join([str(x) for x in ans][::-1])
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """

44. 通配符匹配

题目描述

给定一个字符串 (s) 和一个字符模式 (p),实现一个支持 ‘?’ 和 ‘’ 的通配符匹配。 ‘?’ 可以匹配任何单个字符。 ‘
可以匹配任意字符串(包括空字符串)。 两个字符串完全匹配才算匹配成功。

说明:

s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。

示例 1:

输入: s = “aa” p = “a”
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。

示例 2:

输入: s = “aa” p = “*”
输出: true
解释: * 可以匹配任意字符串。

示例 3:

输入: s = “cb”
p = “?a”
输出: false 解释: ‘?’ 可以匹配 ‘c’, 但第二个 ‘a’ 无法匹配 ‘b’。

示例 4:

输入: s = “adceb”
p = "* a* b” 输出: true
解释: 第一个 *可以匹配空字符串, 第二个 *可以匹配字符串“dce”.

示例 5:

输入: s = “acdcb” p = “a*c?b” 输出: false

思路

(动态规划) O(nm)
1.设状态 f(i,j) 表示 s 串的前 i 个字符与 p 串的前 j 个字符是否匹配。这里的有效下标从 1 开始。
2.假设 s 串的长度为 n,p 串的长度为 m。
3.初始化 f(0,0)=true,其余待定。
4.转移方程,假设 s 串的第 i 个字符为变量 x,p 串的第 j 个字符为变量 y。

c++代码

class Solution {
public:
    bool isMatch(string s, string p) {
       int n = s.size();
       int m = p.size();
       s=' '+s;
       p=' '+p;
      vector<vector<bool>>f(n+1,vector<bool>(m+1));
      f[0][0] = true;
      for(int i =0;i<=n;i++)
      {
          for(int j =1;j<=m;j++)
          {
              if(p[j]=='*')
                f[i][j]=f[i][j-1]||i&&f[i-1][j];
              else
                f[i][j]=(s[i]==p[j]||p[j]=='?')&&i&&f[i-1][j-1];
          }
      }
      return f[n][m];
    }
};

python代码

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        n = len(s)
        m = len(p)
        s = ' ' + s
        p = ' ' + p
        f = [[False for _ in range(m + 1)] for _ in range(n + 1)]
        f[0][0] = True

        for i in range(0, n + 1):
            for j in range(1, m + 1):
                if p[j] == '*':
                    f[i][j] = f[i][j - 1] or i and f[i - 1][j]
                else:
                    f[i][j] = (p[j] == s[i] or p[j] == '?') and i and f[i - 1][j - 1]
        return bool(f[n][m])

45. 跳跃游戏 II

给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

你的目标是使用最少的跳跃次数到达数组的最后一个位置。

示例:

输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。 从下标为 0 跳到下标为 1 的位置,跳 1
步,然后跳 3 步到达数组的最后一个位置。

思路

(动态规划,贪心优化) O(n)
首先定义两个指针 last 和 i,数组 f[i] 表示到达 i 所需要的最少步数。 定义 last
为第一次到达 i 时上一步的位置,last 从 0 开始。 根据贪心得知,令 f[i] = f[last] + 1 后,f[i]
就会是最优值。 故可以根据 i 来让 last 向后移动,找到最早的可以一步到达 i 的位置,然后根据 f[last] 更新 f[i]。

c++代码

class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums.size();
        vector<int>f(n);
        //初始化
        f[0]=0;
        int last =0;
        for(int i =1;i<n;i++)
        {
            while(i>nums[last]+last)last++;
            f[i] = f[last]+1;
        }
        return f[n-1];
    }
};

python 代码

class Solution(object):
    def jump(self, nums):
        n = len(nums)
        f = [0 for _ in range(n)]
        last = 0
        for i in range(1, n):
            while i > last + nums[last]:
                last += 1
            f[i] = f[last] + 1
        return f[n - 1]
        """
        :type nums: List[int]
        :rtype: int
        """
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页