【每日三题】贪心大法好

169 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情 >>


每日三刷,剑指千题

计划简介:

  • 每日三题,以中等题为主,简单题为辅进行搭配。保证质量题1道,数量题3道。
  • 每日早通勤在LeetCode手机端选题,思考思路,没答案的直接看题解。
  • 每日中午进行编码,时间控制在一小时之内。
  • 下班前半小时进行整理总结,并发布到掘金每日更文活动。

说明:

  • 基于以前的刷题基础,本次计划以中等题为主,大部分中等题都可以拆分为多个简单题,所以数量保证3,质量保证一道中等题即可。
  • 刷题顺序按照先刷链表、二叉树、栈、堆、队列等基本数据结构,再刷递归、二分法、排序、双指针等基础算法,最后是动态规划、贪心、回溯、搜索等复杂算法。
  • 刷题过程中整理相似题型,刷题模板。
  • 目前进度 178/1000

今日题型

贪心算法:只考虑当前最优解。

[122]买卖股票的最佳时机 II

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润

示例 1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
     总利润为 4 + 3 = 7

解析

典型贪心

Code

class Solution {
    public int maxProfit(int[] prices) {
        // 贪心算法 在每一步总是做出在当前看来最好的选择。
        // 对于 「今天的股价 - 昨天的股价」,得到的结果有 3 种可能:
        // ① 正数,② 0,③负数。贪心算法的决策是: 只加正数 。
        if (prices.length < 2){
            return 0;
        }
​
        int ans = 0;
        for (int i = 1; i < prices.length; i++) {
            if (prices[i]- prices[i-1]>0){
                ans += prices[i]- prices[i-1];
            }
        }
        return ans;
    }
}

[397]整数替换

给定一个正整数 n ,你可以做如下操作:

  1. 如果 n 是偶数,则用 n / 2替换 n
  2. 如果 n 是奇数,则可以用 n + 1n - 1替换 n

返回 n 变为 1 所需的 最小替换次数

示例 1:

输入:n = 8
输出:3
解释:8 -> 4 -> 2 -> 1

示例 2:

输入:n = 7
输出:4
解释:7 -> 8 -> 4 -> 2 -> 17 -> 6 -> 3 -> 2 -> 1

解析

奇数时加1还是减1需要根据二进制前一位是0还是1判断。

Code

class Solution {
        public int integerReplacement(int _n) {
            long n = _n;
            int ans = 0;
            while (n != 1) {
                if (n % 2 == 0) {
                    n /= 2;
                } else {
                    if (n != 3 && (n + 1) / 2 % 2 == 0) n++;
                    else n--;
                }
                ans++;
            }
            return ans;
        }
    }

[402]移掉 K 位数字

给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。

示例 1 :

输入:num = "1432219", k = 3
输出:"1219"
解释:移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219 。

解析

如果当前数字比前面的小,则移除高位且大的数字,让后面小的移到高位。

最后截取需要的位数,并且去掉最高位的 0 。

Code

class Solution {
        public String removeKdigits(String num, int k) {
            // 不能简单的移除 0 或者 最高位
            // 如果每次都按最优的决策?即 k=1时怎么做最优?
//        如果当前遍历的数比栈顶大,符合递增,是满意的,让它入栈。
//        如果当前遍历的数比栈顶小,栈顶立刻出栈
            int remain = num.length() - k;
            Stack<Character> stack = new Stack<>();
            stack.push(num.charAt(0));
            for (int i = 1; i < num.length(); i++) {
                while (k > 0 && !stack.isEmpty() && num.charAt(i) < stack.peek()) {
                    stack.pop();
                    k--;
                }
                stack.push(num.charAt(i));
            }
            StringBuilder ans = new StringBuilder();
            while (!stack.isEmpty()) {
                ans.append(stack.pop());
            }
            String s = ans.reverse().substring(0, remain);
            while (s.startsWith("0")) {
                s = s.substring(1);
            }
            if (s.equals("")) {
                s = "0";
            }
            return s;
        }
    }

\