LeetCode解题记录(贪心算法)(二)
1. 前言
由于后面还有很多题型要写,贪心算法目前可能就到此为止了,上一篇博客的地址为
LeetCode解题记录(贪心算法)(一)
下面正式开始我们的刷题之旅
2. 贪心
763. 划分字母区间(中等)
思路
想切割,要有首尾两个指针,确定了结尾指针,就能确定下一个切割的开始指针。
遍历字符串,如果已扫描部分的所有字符,都只出现在已扫描的范围内,即可做切割。
注意 : 贪心的思想为,只要是扫描过的字符,都出现在我扫描的范围之类,我就切割,不去考虑其他的条件,这样能保证切割的数量最多
代码实现思路
- result 用来保存结果
- start end,片断的首尾指针
- map 存放每一个字符的最远位置
首先通过一个map,记录了每个字符的最远的位置,接下来遍历字符串,end是用来记录,当前已经扫描的字符串的最远的出现的位置,如果当前的位置,等于扫描的字符串的最远位置,则,可以证明,到达了切割的条件,然后切割,存到result里
class Solution {
public:
vector<int> partitionLabels(string S) {
vector<int> result;
unordered_map<char, int> map; //记录char c 和其最后出现位置的 map
int start = 0, end = 0;
// 初始化map,记录每一个字符的最后位置
for (int i = 0; i < S.size(); i ++) {
map[S[i]] = i;
}
for (int i = 0; i < S.size(); i ++) {
end = max(end, map[S[i]]);//记录已扫描字符的最后一次出现的位置
if (i == end) {//说明后面的片段没有出现重复的字母了
result.push_back(end - start + 1);//记录结果
start = i + 1;
}
}
return result;
}
};
406. 根据身高重建队列(中等)
解题思路
贪心算法:按照身高从高到低进行排序,矮的放后面,因为矮的即使放在了高的前面,也不会对之前高的产生影响;但高的放在前面,对矮的结果就会产生影响了。
重写 compare() 方法:身高相同,按照个数升序排序;身高不同,按照身高降序排序。
public int compare(int[] o1, int[] o2) {
// 先按身高降序,若身高相同则按 k 值升序。
return o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0];
}
第二个数字作为索引位置,把数组放在目标索引位置上,如果原来有数了,会往后移。(在一个 ListList 中的指定位置插入一个元素,当前指定位置的元素会往后面移动一个位置。)
遍历排序后的数组,根据 K 插入到 K 的位置上。
class Solution {
public int[][] reconstructQueue(int[][] people) {
int n = people.length;
int m = people[0].length;
if (n == 0 || m == 0) return new int[0][0];
Arrays.sort(people, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
// 先按身高降序,若身高相同则按 k 值升序。
return o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0];
}
});
// 遍历排序后的数组,根据 K 插入到 K 的位置上。
List<int[]> list = new ArrayList<>();
for (int[] i : people) {
list.add(i[1], i);
}
return list.toArray(new int[list.size()][2]);
}
}
665. 非递减数列
给你一个长度为 n 的整数数组,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。
我们是这样定义一个非递减数列的: 对于数组中任意的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]。
示例 1:
输入: nums = [4,2,3]
输出: true
解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。
示例 2:
输入: nums = [4,2,1]
输出: false
解释: 你不能在只改变一个元素的情况下将其变为非递减数列。
提示:
1 <= n <= 10 ^ 4
10 ^ 5 <= nums[i] <= 10 ^ 5
题解:
贪心算法
本题是要维持一个非递减的数列,所以遇到递减的情况时(nums[i] > nums[i + 1]),要么将前面的元素缩小,要么将后面的元素放大。
但是本题唯一的易错点就在这,
如果将nums[i]缩小,可能会导致其无法融入前面已经遍历过的非递减子数列;
如果将nums[i + 1]放大,可能会导致其后续的继续出现递减;
所以要采取贪心的策略,在遍历时,每次需要看连续的三个元素,也就是瞻前顾后,遵循以下两个原则:
需要尽可能不放大nums[i + 1],这样会让后续非递减更困难;
就是能不放大就不放大,尽量与前面持平
如果缩小nums[i],但不破坏前面的子序列的非递减性;
算法步骤:
遍历数组,如果遇到递减:
还能修改:
修改方案1:将nums[i]缩小至nums[i + 1];
这个方案是,用i-1,i,i+1,来表示三个数的位置,其中i是我们发现大于i+1的数,那么当i+1大于i-1的时候,我们应该将i缩小至i+1,为什么呢,你想啊,你右边的数比你小,你左边的数比你小,但是呢,你右边的数比你左边的数高,你是不是只需要和你右边的一样高,就能保持非递减?如果你不这样,你让右边的数增加,这就违反了上面的第一条原则:需要尽可能不放大nums[i + 1],这样会让后续非递减更困难,因为这种情况,我们的选择是缩小i
修改方案2:将nums[i + 1]放大至nums[i];
这种情况是什么呢,与上一种相反,你左边右边的数都比你小,但是你右边的数比你左边的数要小,这个时候我们就应该将右边的数放大,放大至nums[i],也就是你的大小,这种情况下是没有争论的,只能将右边的数放大,不明白的同学可以自己在纸上画一画
如果不能修改了:直接返回false;
这个代码需要修改两个地方,显然不符合题目要求,返回false
代码如下
flag 代表修改机会,因为只有一次,所以用掉了,flag就变成false
class Solution {
public:
bool checkPossibility(vector<int>& nums)
{
if (nums.size() == 1) return true;
bool flag = nums[0] <= nums[1] ? true : false; // 标识是否还能修改
// 遍历时,每次需要看连续的三个元素
for (int i = 1; i < nums.size() - 1; i++)
{
if (nums[i] > nums[i + 1]) // 出现递减
{
if (flag) // 如果还有修改机会,进行修改
{
if (nums[i + 1] >= nums[ i - 1])// 修改方案1
nums[i] = nums[i + 1];
else // 修改方案2
nums[i + 1] = nums[i];
flag = false; // 用掉唯一的修改机会
}
else // 没有修改机会,直接结束
return false;
}
}
return true;
}
};
执行结果
3. 总结
对不起各位,我算法这块更新的实在是太慢了,不过最近真的很忙很忙,当然有时候我也会娱乐一下,没有做到自律,下个星期我还准备开始写计算机网络和操作系统的专栏,所以算法这块,我尽量多写(其实我就是懒,有时候晚上回家真的好累,不想写算法题,,,,)
总之,下个星期,继续努力,与昨天的自己比较!
LeetCode解题记录(贪心算法)(二)的更多相关文章
- LeetCode解题记录(贪心算法)(一)
1. 前言 目前得到一本不错的算法书籍,页数不多,挺符合我的需要,于是正好借这个机会来好好的系统的刷一下算法题,一来呢,是可以给部分同学提供解题思路,和一些自己的思考,二来呢,我也可以在需要复习的时候 ...
- C#LeetCode刷题-贪心算法
贪心算法篇 # 题名 刷题 通过率 难度 44 通配符匹配 17.8% 困难 45 跳跃游戏 II 25.5% 困难 55 跳跃游戏 30.6% 中等 122 买卖股票的最佳时机 II C ...
- [leetcode解题记录]Jump Game和Jump Game II
Jump Game Given an array of non-negative integers, you are initially positioned at the first index o ...
- Leetcode解题记录
尽量抽空刷LeetCode,持续更新 刷题记录在github上面,https://github.com/Zering/LeetCode 2016-09-05 300. Longest Increasi ...
- LeetCode解题记录(双指针专题)
1. 算法解释 双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务.也可以延伸到多个数组的多个指针. 若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域 ...
- LeetCode 135 Candy(贪心算法)
135. Candy There are N children standing in a line. Each child is assigned a rating value. You are g ...
- 「面试高频」二叉搜索树&双指针&贪心 算法题指北
本文将覆盖 「字符串处理」 + 「动态规划」 方面的面试算法题,文中我将给出: 面试中的题目 解题的思路 特定问题的技巧和注意事项 考察的知识点及其概念 详细的代码和解析 开始之前,我们先看下会有哪些 ...
- 基于贪心算法的几类区间覆盖问题 nyoj 12喷水装置(二) nyoj 14会场安排问题
1)区间完全覆盖问题 问题描述:给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间),求最少使用多少条线段可以将整个区间完全覆盖 样例: 区间长度8,可选的覆盖线段[2,6],[1, ...
- LEETCODE —— Best Time to Buy and Sell Stock II [贪心算法]
Best Time to Buy and Sell Stock II Say you have an array for which the ith element is the price of a ...
随机推荐
- Python+Selenium学习笔记5 - python官网的tutorial - 交互模式下的操作
这篇笔记主要是从Python官网的Tutorial上截取下来,再加上个人理解 1. 在交互模式下,下划线'_'还可以表示上一步的计算结果 2.引号转义问题. 从下图总结的规律是,字符串里的引号如果和引 ...
- NNVM Compiler,AI框架的开放式编译器
NNVM Compiler,AI框架的开放式编译器 深度学习已变得无处不在且不可或缺.在多种平台(例如手机,GPU,IoT设备和专用加速器)上部署深度学习工作负载的需求不断增长.宣布了TVM堆栈,以弥 ...
- 2.5D Visual Sound:CVPR2019论文解析
2.5D Visual Sound:CVPR2019论文解析 论文链接: http://openaccess.thecvf.com/content_CVPR_2019/papers/Gao_2.5D_ ...
- CodeGen标记循环
CodeGen标记循环 标记循环是一个模板文件构造,它允许您迭代CodeGen拥有的标记信息的集合.为了使用标记循环,必须基于至少定义了一个字段标记的存储库结构生成代码. 标 ...
- python_selenium_PO模式下显示等待、隐式等待封装,结合Excel读取元素可取默认等待时间配置
basepage中等待的封装 def implicitly_wait(self): self.driver.implicitly_wait(5)def wait(self): time.sleep(5 ...
- jvm相关自我总结和 VisualVM工具的使用
idea 二个工具: jclasslib Hexview jdk监控工具 VisualVM工具的使用: https://www.ibm.com/developerworks/cn/java/j-lo- ...
- 这 7 个 Linux 命令,你是怎么来使用的?
使用 Linux 系统的开发者,很多人都有自己喜欢的系统命令,下面这个几个命令令是我平常用的比较多的,分享一下. 我不会教科书般的罗列每个指令的详细用法,只是把日常开发过程中的一些场景下,经常使用的命 ...
- 【NX二次开发】多种变换
变换的种类: uf5942 矩阵乘积变换 uf5943 平移变换 uf5944 缩放变换 uf5945 旋转变换 uf5946 镜像变换 最后使用 uf5947 实现uf5942-uf5946的变换. ...
- [源码解析] 深度学习分布式训练框架 horovod (5) --- 融合框架
[源码解析] 深度学习分布式训练框架 horovod (5) --- 融合框架 目录 [源码解析] 深度学习分布式训练框架 horovod (5) --- 融合框架 0x00 摘要 0x01 架构图 ...
- 手把手使用Python进行语音合成,文字转语音
目录 0. 太长不看系列,直接使用 1. Python调用标贝科技语音合成接口,实现文字转语音 1.1 环境准备: 1.2 获取权限 1.2.1 登录 1.2.2 创建新应用 1.2.3 选择服务 1 ...