【算法题解】 Day5 贪心

简介: 今天的算法是 「贪心」 相关,“算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,以实战习题的形式理解算法,使用算法。”

121. 买卖股票的最佳时机

题目

121. 买卖股票的最佳时机 难度:easy

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入: prices = [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

 

方法一:贪心

思路

这里的话,贪心思想是比较适用的,即想获取最大利润,那么就要买入的时候价格相对最低,卖出的时候价格相对最高,所以需要找出给定数组中两个数字之间的最大差值(即,最大利润);

形式上,对于每组 i 和 j(其中 j > i)我们需要找出 max(prices[j]−prices[i])

 

解题

Python:

# 此方法会超时
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        ans = 0
        for i in range(len(prices)):
            for j in range(i + 1, len(prices)):
                ans = max(ans, prices[j] - prices[i])
        return ans

Java:

public class Solution {
    public int maxProfit(int[] prices) {
        int maxprofit = 0;
        for (int i = 0; i < prices.length - 1; i++) {
            for (int j = i + 1; j < prices.length; j++) {
                int profit = prices[j] - prices[i];
                if (profit > maxprofit) {
                    maxprofit = profit;
                }
            }
        }
        return maxprofit;
    }
}

 

方法二:动态规划

思路

上述方法一只是展示了一下「贪心」算法的思想,但实际是,两次遍历的时间复杂度非常高,因此我们需要对此进行优化,做到一次遍历,下边就使用「动态规划」来进行优化;

假设给定的数组为:[7, 1, 5, 3, 6, 4]

如果我们在图表上绘制给定数组中的数字,我们将会得到:

Profit Graph

我们来假设自己来购买股票。随着时间的推移,每天我们都可以选择出售股票与否。那么,假设在第 i 天,如果我们要在今天卖股票,那么我们能赚多少钱呢?

显然,如果我们真的在买卖股票,我们肯定会想:如果我是在历史最低点买的股票就好了!太好了,在题目中,我们只要用一个变量记录一个历史最低价格 minprice,我们就可以假设自己的股票是在那天买的。那么我们在第 i 天卖出股票能得到的利润就是 prices[i] - minprice

因此,我们只需要遍历价格数组一遍,记录历史最低点,然后在每一天考虑这么一个问题:如果我是在历史最低点买进的,那么我今天卖出能赚多少钱?当考虑完所有天数之时,我们就得到了最好的答案。

 

解题

Python:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        inf = int(1e9)
        minprice = inf
        maxprofit = 0
        for price in prices:
            maxprofit = max(price - minprice, maxprofit)
            minprice = min(price, minprice)
        return maxprofit

Java:

public class Solution {
    public int maxProfit(int prices[]) {
        int minprice = Integer.MAX_VALUE;
        int maxprofit = 0;
        for (int i = 0; i < prices.length; i++) {
            if (prices[i] < minprice) {
                minprice = prices[i];
            } else if (prices[i] - minprice > maxprofit) {
                maxprofit = prices[i] - minprice;
            }
        }
        return maxprofit;
    }
}

 

409. 最长回文串

题目

409. 最长回文串 难度:easy

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

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

示例 1:

输入: s = "abccccdd"
输出: 7
解释: 我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。

示例 2:

输入: s = "a"
输入: 1

提示:

  • 1 <= s.length <= 2000
  • s 只由小写 和/或 大写英文字母组成

 

方法一:贪心

思路

根据题意,我们主要将字符串重新构造形成一个最长的回文串,因此,需要先对每个字符进行统计,

count = []
for ..:
    # ch 表示字符串中的单个字符
    count[ch] += 1

然后根据回文串的性质,对其进行处理:如果该字符一共出现了偶数次,那就一股脑的放在两侧,如果出现了奇数次,则需要慎重选择了;

因为在回文串中,偶数个字符并不会对回文造成影响,但奇数个会,比如起始有 aba,这时候来了两个 c,可以直接加入两侧变成 cabac,还是回文,如果是一个 c 呢,那么插入在哪里都会出现问题,因为原字符串中已经有一个字符的个数是奇数的了;

因此得出结论,回文串中允许出现字符的个数为奇数,但只能有一个字符的个数为奇数,所以为了得到最长回文串,所以对个数为奇数的字符,我们要选择长度最长的;

 

解题

Python:

class Solution:
    def longestPalindrome(self, s: str) -> int:
        ans = 0
        count = collections.Counter(s)
        for v in count.values():
            ans += v // 2 * 2
            if ans % 2 == 0 and v % 2 == 1:
                ans += 1
        return ans

Java:

class Solution {
    public int longestPalindrome(String s) {
        int[] count = new int[128];
        int length = s.length();
        for (int i = 0; i < length; ++i) {
            char c = s.charAt(i);
            count[c]++;
        }

        int ans = 0;
        for (int v: count) {
            ans += v / 2 * 2;
            if (v % 2 == 1 && ans % 2 == 0) {
                ans++;
            }
        }
        return ans;
    }
}

 

后记

📝 上篇精讲: 【算法题解】 Day4 链表
💖 我是  𝓼𝓲𝓭𝓲𝓸𝓽,期待你的关注;
👍 创作不易,请多多支持;
🔥 系列专栏: 算法题解
目录
相关文章
|
4天前
|
算法
【算法】——动态规划题目讲解
【算法】——动态规划题目讲解
|
4天前
|
算法 容器
『 基础算法题解 』之双指针(下)
『 基础算法题解 』之双指针(下)
|
4天前
|
算法 测试技术 容器
『 基础算法题解 』之双指针(上)
『 基础算法题解 』之双指针(上)
|
算法 Java 测试技术
【LeetCode】 53. 最大子序和(贪心算法)
53. 最大子序和(贪心算法)
62 0
|
算法
LeetCode 605. 种花问题(贪心算法)
LeetCode 605. 种花问题(贪心算法)
65 0
|
算法 机器人 Java
【算法题解】 Day12 动态规划
今天的算法是 「动态规划」 相关,“算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,以实战习题的形式理解算法,使用算法。”
63 0
|
算法 Java Python
【算法题解】 Day25 动态规划
今天的算法是 「动态规划」 相关,“算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,以实战习题的形式理解算法,使用算法。”
56 0
|
算法 Java Python
【算法题解】 Day24 动态规划
今天的算法是 「动态规划」 相关,“算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,以实战习题的形式理解算法,使用算法。”
54 0
|
算法 Java 索引
【算法题解】 Day26 双指针
今天的算法是 「双指针」 相关,“算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,以实战习题的形式理解算法,使用算法。”
72 0
|
算法 Java 索引
【算法题解】 Day28 双指针
今天的算法是 「双指针」 相关,“算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,以实战习题的形式理解算法,使用算法。”
52 0