代码随想录_贪心系列
目录
1.leetcode455 分发饼干
这里的局部最优解其实就是:大饼干先满足大胃口的
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int contentPerson = 0, i = 0, j = 0;
while(j < s.length) {
if(s[j] >= g[i]) {
contentPerson++;
j++;
i++;
if(i >= g.length) break;
}
else {
j++;
}
}
return contentPerson;
}
}
leetcode 122买卖股票的最佳时机II
局部最优:只要有利润我就要->全局最优:利润最大
class Solution {
public int maxProfit(int[] prices) {
int ans = 0;
for(int i = 1; i < prices.length; i++) {
int ret = prices[i]-prices[i-1];
ans += ret > 0 ? ret: 0;
}
return ans;
}
}
leetcode55. 跳跃游戏
class Solution {
// 局部最优->我能跳N步,接下来N步中我选一个,他+他能跳的最远的接着跳
public boolean canJump(int[] nums) {
if(nums.length==1) return true;
int maxJumpIdx = 0,idx=0,lastIdx = nums.length -1;
while(idx < nums.length && nums[idx] != 0 && maxJumpIdx <= lastIdx) {
int nextIdx = Integer.MIN_VALUE, nextStepDis= Integer.MIN_VALUE;
for(int i = idx+1; i <= idx+nums[idx] && i < nums.length; i++) {
if(nums[i] + i > nextStepDis) {
nextStepDis = nums[i] + i;
nextIdx = i;
}
}
idx = nextIdx;
maxJumpIdx = nextStepDis;
}
return maxJumpIdx >= lastIdx;
}
}
标准答案写的好简洁:
class Solution {
public boolean canJump(int[] nums) {
if(nums.length == 1) return true;
int cover = 0;
for(int i = 0; i <= cover; i++) {
cover = Math.max(i+nums[i], cover);
if(cover >= nums.length-1) return true;
}
return false;
}
}
leetcode45. 跳跃游戏II
局部最优:每次跳跃都尝试覆盖最远距离,如果不能一次确定最远的距离(因为不知道下一个要跳跃到哪里,那么可以以下次跳跃最远距离为标准)。
每次覆盖最远距离,那么最后一定是最小的步骤可以跳完。
class Solution {
public int jump(int[] nums) {
int ans = 0, curDistance = 0, nextDistance = 0;
for(int i = 0; i < nums.length; i++) {
nextDistance = Math.max(i + nums[i], nextDistance);
if(i == curDistance) {
if(i < nums.length -1) {
ans++;
curDistance = nextDistance;
if(curDistance >= nums.length-1) break;
} else break;
}
}
return ans;
}
}
leetcode 1005 K次取反后最大值
说白了就是贪心,让绝对值最大的负数变成正的;如果k还有没用完的,就让绝对值最小的变成负的。
class Solution {
public int largestSumAfterKNegations(int[] nums, int k) {
nums = IntStream.of(nums)
.boxed()
.sorted((o1, o2)-> Math.abs(o2)-Math.abs(o1))
.mapToInt(Integer::intValue).toArray();
int len = nums.length;
for(int i = 0; i < len; i++) {
if(nums[i] < 0 && k > 0) {
nums[i] = -nums[i];
k--;
}
}
if(k % 2 == 1) nums[len-1] = -nums[len-1];
return Arrays.stream(nums).sum();
}
}
思路没错,但我写出的就各种bug,真是让人无奈。
我的错误题解:
class Solution {
private int firstNegative(int[] nums) {
int l = 0, r = nums.length-1;
// the first >= 0
while (l < r) {
int mid = l+r >>1;
if(nums[mid] >= 0) r = mid;
else l = mid +1;
}
return r;
}
public int largestSumAfterKNegations(int[] nums, int k) {
// 尽量把所有的负数都翻过来
// k > number of negetive numbers % len % 2 选择绝对值最小的那个
// k == 绝对值之和
// k < number of 进行排序,选择绝对值最大的那个
Arrays.sort(nums);
int firstNeg = firstNegative(nums);
for(int i = 0; i < k && i < firstNeg; i++) {
nums[i] = -nums[i];
}
if(k > firstNeg) {
if(firstNeg > 0) k %= firstNeg;
k %= 2;
if(k == 1) {
Arrays.sort(nums);
nums[0] = -nums[0];
}
}
return Arrays.stream(nums).sum();
}
}
leetcode 134加油站
如果总共的求和大于零,那么一定可以跑完全程。
对某一段求和,一旦他们小于0,必须从起始位置开始。
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int curSum = 0, totalSum = 0, startIdx=0;
for(int i = 0; i < gas.length; i++) {
int ret = gas[i] - cost[i];
curSum += ret;
totalSum += ret;
if(curSum < 0) {
startIdx=i+1;
curSum = 0;
}
}
if(totalSum < 0) return -1;
return startIdx;
}
}
leetcode 406根据高度重建数组
如果是两个维度,不要妄图一口气吃成一个胖子,首先确定一个->逐步思维
有两个维度,h和k,因为k依赖于h,所以一定要使用h。
先根据h进行排序,得到排序后的数组。
然后再根据k来进行排序。如果排序不好做可以进行插入。
class Solution {
public int[][] reconstructQueue(int[][] people) {
// 比较函数为一个labmda表达式
// 如果运算结果小于零,那么就是否,不需要交换位置,那么就是按正常的顺序作差。反之逆序作差。
Arrays.sort(people, (a,b) -> {
if(a[0]==b[0]) return a[1] - b[1];
return -(a[0]-b[0]);
});
LinkedList<int[]> q =new LinkedList();
for(int[] p: people) {
q.add(p[1], p);
}
return q.toArray(new int[people.length][]);
}
}
leetcode425 用最少的箭引爆气球
class Solution {
public int findMinArrowShots(int[][] points) {
Arrays.sort(points, (a,b)->{
return Integer.compare(a[0],b[0]);
});
int result = 1;
for(int i = 1; i < points.length; i++) {
if(points[i][0] > points[i-1][1]) result++;
else {
points[i][1] = Math.min(points[i][1], points[i-1][1]);
}
}
return result;
}
}
leetcode453 无重叠区间
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
if(intervals.length == 0) return 0;
Arrays.sort(intervals, (o1, o2)->{
return o1[1] - o2[1];
});
int count = 1, end = intervals[0][1];
for(int i = 1; i < intervals.length; i++) {
if(end <= intervals[i][0]) {
end = intervals[i][1];
count++;
}
}
return intervals.length-count;
}
}
leetcode 划分字母区间
class Solution {
public List<Integer> partitionLabels(String s) {
List<Integer> ans = new ArrayList();
if(s.length()==0) return ans;
int[] hash = new int[27];
for(int i = 0; i < s.length(); i++) {
hash[s.charAt(i)-'a'] = i;
}
int maxCover = Integer.MIN_VALUE, startIdx = 0;
for(int i = 0; i < s.length(); i++) {
int thisEnd = hash[s.charAt(i) - 'a'];
maxCover = Math.max(thisEnd, maxCover);
if(i == maxCover) {
ans.add(i - startIdx + 1);
startIdx = i + 1;
}
}
return ans;
}
}