代码随想录_贪心系列

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;
    }
}
posted @ 2022-05-13 19:53  明卿册  阅读(49)  评论(0编辑  收藏  举报