leecode更新

This commit is contained in:
markilue 2023-02-12 13:37:07 +08:00
parent f72765f983
commit 4b8e8a7d65
4 changed files with 325 additions and 1 deletions

View File

@ -0,0 +1,129 @@
package com.markilue.leecode.greedy;
import org.junit.Test;
import java.util.Arrays;
import java.util.Comparator;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.greedy
*@Author: markilue
*@CreateTime: 2023-02-12 10:28
*@Description:
* TODO 力扣435题 无重叠区间:
* 给定一个区间的集合 intervals 其中 intervals[i] = [starti, endi] 返回 需要移除区间的最小数量使剩余区间互不重叠
*@Version: 1.0
*/
public class T11_1_EraseOverlapIntervals {
@Test
public void test() {
// int[][] intervals = {{
// 1, 2
// }, {
// 2, 3
// }, {
// 3, 4
// }, {
// 1, 3
// }};
int[][] intervals = {{0, 2}, {1, 3}, {2, 4}, {3, 5}, {4, 6}};
System.out.println(eraseOverlapIntervals(intervals));
}
/**
* 思路与上题11的射爆重叠气球的思路类似只不过这题是需要去除的区间还是按xstart进行排序
* 速度击败52.7%内存击败15.57% 50ms
* @param intervals
* @return
*/
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
for (int[] interval : intervals) {
System.out.println(Arrays.toString(interval));
}
int threshold = intervals[0][1];
int result = 0;
for (int i = 1; i < intervals.length; i++) {
if (intervals[i][0] < threshold) {
//需要移除
result++;
threshold = Math.min(intervals[i][1], threshold);
} else {
threshold = intervals[i][1];
}
}
return result;
}
/**
* 官方思路根据xend右排序记录不会重叠的位置最后的结果就是总区间数n-不会重叠区间ans
* 因为是按右排序所以不用考虑子集情况
* 速度击败98.28%内存击败71% 47ms
* @param intervals
* @return
*/
public int eraseOverlapIntervals1(int[][] intervals) {
if (intervals.length == 0) {
return 0;
}
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[1] - o2[1];
}
});
int n = intervals.length;
int right = intervals[0][1];
int ans = 1;
for (int i = 1; i < n; i++) {
if (intervals[i][0] >= right) {
ans++;
right = intervals[i][1];
}
}
return n - ans;
}
/**
* 官方动态规划法:时间复杂度比较高O(n^2)
* @param intervals
* @return
*/
public int eraseOverlapIntervals2(int[][] intervals) {
if (intervals.length == 0) {
return 0;
}
Arrays.sort(intervals, new Comparator<int[]>() {
public int compare(int[] interval1, int[] interval2) {
return interval1[0] - interval2[0];
}
});
int n = intervals.length;
int[] f = new int[n];
Arrays.fill(f, 1);
for (int i = 1; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (intervals[j][1] <= intervals[i][0]) {
f[i] = Math.max(f[i], f[j] + 1);
}
}
}
return n - Arrays.stream(f).max().getAsInt();
}
}

View File

@ -0,0 +1,103 @@
package com.markilue.leecode.greedy;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.greedy
*@Author: markilue
*@CreateTime: 2023-02-12 11:14
*@Description:
* TODO 力扣763题 划分字母区间:
* 给你一个字符串 s 我们要把这个字符串划分为尽可能多的片段同一字母最多出现在一个片段中
* 注意划分结果需要满足将所有划分结果按顺序连接得到的字符串仍然是 s
* 返回一个表示每个字符串片段的长度的列表
*@Version: 1.0
*/
public class T11_2_PartitionLabels {
@Test
public void test() {
String s = "eccbbbbdec";
System.out.println(partitionLabels(s));
}
/**
* 思路:Map记录<num,startIndex>,如果num不在map的话count+1重新分片并把它加入map
* 速度击败7.77%内存击败9.27% 10ms
* @param s
* @return
*/
public List<Integer> partitionLabels(String s) {
char[] chars = s.toCharArray();
HashMap<Character, Integer> map = new HashMap<>();//<char,startIndex>
List<Integer> result = new ArrayList<>();
for (int i = 0; i < chars.length; i++) {
if (map.containsKey(chars[i])) {
Integer startIndex = map.get(chars[i]);
//看看需要更改result的位置
int lastThreshold = -1;//count转index
int count = 0;
for (; count < result.size(); count++) {
int index=result.get(count);
if (startIndex <= lastThreshold+index) {//count变index
//撞了
result.set(count, i - lastThreshold);
break;
}
lastThreshold += index;
}
//移除撞了之后的全部变成一个
for (; result.size() > count + 1; ) {
result.remove(result.size() - 1);
}
} else {
//没遇到过
result.add(1);
map.put(chars[i], i);
}
}
return result;
}
/**
* 代码随想录思路:本质上就是看那个字母出现的最远如果遍历到了最远的位置还没有比她更远的那么就把他加入result中从而转换为11.1和11之中完全一样的解法了
* TODO
* 在遍历的过程中相当于是要找每一个字母的边界如果找到之前遍历过的所有字母的最远边界说明这个边界就是分割点了此时前面出现过所有字母最远也就到这个边界了
* 可以分为如下两步
* 1.统计每一个字符最后出现的位置
* 2.从头遍历字符并更新字符的最远出现下标如果找到字符最远出现位置下标和当前下标相等了则找到了分割点
* 速度击败98.47% 内存击败38.58% 2ms
* @param S
* @return
*/
public List<Integer> partitionLabels1(String S) {
List<Integer> list = new LinkedList<>();
int[] edge = new int[26];
char[] chars = S.toCharArray();
for (int i = 0; i < chars.length; i++) {
edge[chars[i] - 'a'] = i;
}
int idx = 0;
int last = -1;
for (int i = 0; i < chars.length; i++) {
idx = Math.max(idx, edge[chars[i] - 'a']);
if (i == idx) {
list.add(i - last);
last = i;
}
}
return list;
}
}

View File

@ -16,7 +16,7 @@ import java.util.Comparator;
* 给你一个数组 points 返回引爆所有气球所必须射出的 最小 弓箭数 * 给你一个数组 points 返回引爆所有气球所必须射出的 最小 弓箭数
* @Version: 1.0 * @Version: 1.0
*/ */
public class FindMinArrowShots { public class T11_FindMinArrowShots {
@Test @Test
public void test() { public void test() {

View File

@ -0,0 +1,92 @@
package com.markilue.leecode.greedy.second;
import org.junit.Test;
import java.util.Arrays;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.greedy.second
*@Author: markilue
*@CreateTime: 2023-02-12 09:40
*@Description:
* TODO 力扣452题 用最少数量的箭引爆气球:
* 有一些球形气球贴在一堵用 XY 平面表示的墙面上墙面上的气球记录在整数数组 points 其中points[i] = [xstart, xend] 表示水平直径在 xstart xend之间的气球你不知道气球的确切 y 坐标
* 一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出
* 在坐标 x 处射出一支箭若有一个气球的直径的开始和结束坐标为 xstartxend 且满足 xstart x xend则该气球会被 引爆
* 可以射出的弓箭的数量 没有限制 弓箭一旦被射出之后可以无限地前进
* 给你一个数组 points 返回引爆所有气球所必须射出的 最小 弓箭数
*@Version: 1.0
*/
public class T11_FindMinArrowShots {
@Test
public void test(){
int[][] points = {{9, 12}, {1, 10}, {4, 11}, {8, 12}, {3, 9}, {6, 9}, {6, 7}};
System.out.println(findMinArrowShots(points));
}
/**
* 思路:按xstart排序当下一个的xstart大于上一个的xend那么就需要增加一支箭
* 速度击败81.41%内存击败21.99% 53ms
* @param points
* @return
*/
public int findMinArrowShots(int[][] points) {
Arrays.sort(points, (a, b) -> {
if(a[1]!=b[1]){
if(a[1]>b[1]){
return 1;
}else {
return -1;
}
}else {
if(a[0]>b[0]){
return 1;
}else {
return -1;
}
}
});
int threshold = points[0][1];
int arrow = 1;
for (int i = 1; i < points.length; i++) {
if (threshold < points[i][0]) {
//不够了
arrow++;
threshold = points[i][1];
}
}
return arrow;
}
/**
* 代码随想录思路:与本人之前的思路类似按xstart排序如果是自己更新threshold
* 速度击败68.99%内存击败87.94% 54ms
* @param points
* @return
*/
public int findMinArrowShots1(int[][] points) {
// 根据气球直径的开始坐标从小到大排序
// 使用Integer内置比较方法不会溢出
Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0]));
int count = 1; // points 不为空至少需要一支箭
for (int i = 1; i < points.length; i++) {
if (points[i][0] > points[i - 1][1]) { // 气球i和气球i-1不挨着注意这里不是>=
count++; // 需要一支箭
} else { // 气球i和气球i-1挨着
points[i][1] = Math.min(points[i][1], points[i - 1][1]); // 更新重叠气球最小右边界
}
}
return count;
}
}