贪心三两道

1、饼干分配

Description:

Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at most one cookie. Each child i has a greed factor gi, which is the minimum size of a cookie that the child will be content with; and each cookie j has a size sj. If sj >= gi, we can assign the cookie j to the child i, and the child i will be content. Your goal is to maximize the number of your content children and output the maximum number.

Note:

You may assume the greed factor is always positive. 
You cannot assign more than one cookie to one child.

Example 1:

Input: [1,2,3], [1,1]

Output: 1

Explanation: You have 3 children and 2 cookies. The greed factors of 3 children are 1, 2, 3. 
And even though you have 2 cookies, since their size is both 1, you could only make the child whose greed factor is 1 content.
You need to output 1.

Example 2:

Input: [1,2], [1,2,3]

Output: 2

Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2. 
You have 3 cookies and their sizes are big enough to gratify all of the children, 
You need to output 2.

Analysis:

      给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。因为最小的孩子最容易得到满足,所以先满足最小的孩子。贪心策略选择给当前满足度最小的孩子分配第 m 个饼干,第 m 个饼干为可以满足该孩子的最小饼干。假设存在一种最优策略,给该孩子分配第 n 个饼干,并且 m < n。我们可以发现,经过这一轮分配,贪心策略分配后剩下的饼干一定有一个比最优策略来得大。因此在后续的分配中,贪心策略一定能满足更多的孩子。也就是说不存在比贪心策略更优的策略,即贪心策略就是最优策略。

JAVA CODE

public class Solution {
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int i = 0, j = 0;
        while(i < g.length && j < s.length){
            if(g[i] <= s[j]){
                i++;
            }
            j++;
        }
        return i;
    }
}

题目来源455. Assign Cookies

2、根据身高和序号重组队列

Description:

Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers (h, k), where h is the height of the person and k is the number of people in front of this person who have a height greater than or equal to h. Write an algorithm to reconstruct the queue.

Note:

The number of people is less than 1,100.

Example

Input:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]

Output:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]

Analysis:

      为了使插入操作不影响后续的操作,身高较高的学生应该先做插入操作,否则身高较小的学生原先正确插入的第 i个位置可能会变成第 i+1 个位置。身高 h 降序、个数 k 值升序,然后将某个学生插入队列的第 i 个位置中。同时我们借助list的指定idx的添加特性。

JAVA CODE

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        if (people.length < 1 || null == people || people[0].length < 1){
            return new int[0][0];
        }
        //h降序,k升序;身高较高的学生应该先做插入操作
        Arrays.sort(people, new Comparator<int[]>() {
            public int compare(int[] o1, int[] o2) {
                return (o1[0] == o2[0] ? o1[1]-o2[1]: o2[0] - o1[0]);
            }
        });
        List<int[]> list = new ArrayList<>();
        for (int[] arr : people){
            list.add(arr[1], arr);
        }
        return list.toArray(new int[list.size()][]);
    }
}

题目来源:406. Queue Reconstruction by Height

3、投飞镖刺破气球

Description:

There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided input is the start and end coordinates of the horizontal diameter. Since it's horizontal, y-coordinates don't matter and hence the x-coordinates of start and end of the diameter suffice. Start is always smaller than end. There will be at most 104 balloons.

An arrow can be shot up exactly vertically from different points along the x-axis. A balloon with xstart and xend bursts by an arrow shot at x if xstart ≤ x ≤ xend. There is no limit to the number of arrows that can be shot. An arrow once shot keeps travelling up infinitely. The problem is to find the minimum number of arrows that must be shot to burst all balloons.

Example:

Input:
[[10,16], [2,8], [1,6], [7,12]]

Output:
2

Explanation:
One way is to shoot one arrow for example at x = 6 (bursting the balloons [2,8] and [1,6]) and another arrow at x = 11 (bursting the other two balloons).

Analysis:

      气球在一个水平数轴上摆放,可以重叠,飞镖垂直投向坐标轴,使得路径上的气球都被刺破。求解最小的投飞镖次数使所有气球都被刺破。也就是转换为计算不重叠的区间个数。

JAVA CODE

class Solution {
    public int findMinArrowShots(int[][] points) {
        if (points.length < 1){
            return 0;
        }
        Arrays.sort(points, new Comparator<int[]>() {
            public int compare(int[] o1, int[] o2) {
                return o1[1] - o2[1];
            }
        });
        int num = 1;
        int end = points[0][1];
        for (int i = 1; i < points.length; i++){
            if (points[i][0] <= end ){
                continue;
            }
            num++;
            end = points[i][1];
        }
        return num;
    }
}

题目来源:452. Minimum Number of Arrows to Burst Balloons

4、不重叠的区间个数

Description:

Given a collection of intervals, find the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.

Example 1:

Input: [[1,2],[2,3],[3,4],[1,3]]
Output: 1
Explanation: [1,3] can be removed and the rest of intervals are non-overlapping.

Example 2:

Input: [[1,2],[1,2],[1,2]]
Output: 2
Explanation: You need to remove two [1,2] to make the rest of intervals non-overlapping.

Example 3:

Input: [[1,2],[2,3]]
Output: 0
Explanation: You don't need to remove any of the intervals since they're already non-overlapping.

Note:

  1. You may assume the interval's end point is always bigger than its start point.
  2. Intervals like [1,2] and [2,3] have borders "touching" but they don't overlap each other.

Analysis:

       先计算最多能组成的不重叠区间个数,然后用区间总个数减去不重叠区间的个数。在每次选择中,区间的结尾最为重要,选择的区间结尾越小,留给后面的区间的空间越大,那么后面能够选择的区间个数也就越大。按区间的结尾进行排序,每次选择结尾最小,并且和前一个区间不重叠的区间。

JAVA CODE

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        if (intervals.length < 1){
            return 0;
        }
        //根据右端点排序
        Arrays.sort(intervals, new Comparator<int[]>() {
            public int compare(int[] o1, int[] o2) {
                return o1[1]-o2[1];
            }
        });
       // quickSot(intervals, 0, intervals.length-1);
        int cnt = 1;
        int right = intervals[0][1];
        for (int i = 1; i < intervals.length; i++){
            if (intervals[i][0]< right){
                continue;
            }
            right = intervals[i][1];
            cnt++;
        }
        return intervals.length - cnt; 
    }
    private static void quickSot(int[][] arr, int low, int high){
        if (arr.length < 1 || low >= high){
            return;
        }
        int i = low;
        int j = high;
        int right = arr[low][1];
        while (i<j){
            //从左向右找第一个大于right的位置
            while (i<j && right < arr[i][1]){
                i++;
            }
            //从右到左查找第一个小于right的位置
            while (i<j && right >= arr[j][1]){
                j--;
            }
            if (i<j){
                int tmpL = arr[i][0];
                int tmpR = arr[i][1];
                arr[i][0] = arr[j][0];
                arr[i][1] = arr[j][1];
                arr[j][0] = tmpL;
                arr[j][1] = tmpR;
            }
        }

        int tmpL = arr[i][0];
        int tmpR = arr[i][1];
        arr[i][0] = arr[low][0];
        arr[i][1] = arr[low][1];
        arr[low][0] = tmpL;
        arr[low][1] = tmpR;
        quickSot(arr, low, i-1);
        quickSot(arr, i+1, high);

    }
}

5、最多修改一个数成为非递减数组

Description:

Given an array with n integers, your task is to check if it could become non-decreasing by modifying at most 1element.

We define an array is non-decreasing if array[i] <= array[i + 1] holds for every i (1 <= i < n).

Example 1:

Input: [4,2,3]
Output: True
Explanation: You could modify the first 4 to 1 to get a non-decreasing array.

Example 2:

Input: [4,2,1]
Output: False
Explanation: You can't get a non-decreasing array by modify at most one element.

Analysis:

       在出现 nums[i] < nums[i - 1] 时,需要考虑的是应该修改数组的哪个数,使得本次修改能使 i 之前的数组成为非递减数组,并且 不影响后续的操作 。优先考虑令 nums[i - 1] = nums[i],因为如果修改 nums[i] = nums[i - 1] 的话,那么 nums[i] 这个数会变大,就有可能比 nums[i + 1] 大,从而影响了后续操作。还有一个比较特别的情况就是 nums[i] < nums[i - 2],修改 nums[i - 1] = nums[i] 不能使数组成为非递减数组,只能修改 nums[i] = nums[i - 1]。

JAVA CODE

class Solution {
    public boolean checkPossibility(int[] nums) {
        if(nums.length < 1){
            return false;
        }
        int cnt = 0;
        for (int i = 1; i < nums.length && cnt < 2; i++){
            if (nums[i] >= nums[i-1]){
                continue;
            }
            cnt++;
            if (i-2 >= 0 && nums[i-2] > nums[i] ){
                nums[i] = nums[i-1];
            } else {
                nums[i-1] = nums[i];
            }

        }
        return cnt <= 1;
    }
}

6、求子数组最大的和

Description:

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:

Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

JAVA CODE

class Solution {
    public int maxSubArray(int[] nums) {
        if (null == nums || nums.length < 1){
            return 0;
        }
        int preS = nums[0];
        int maxS = preS;
        for (int i = 1; i < nums.length; i++){
            preS = (preS > 0 ? preS + nums[i] : nums[i]);
            maxS = Math.max(preS, maxS);
        }
        return maxS;
    }
}

7、分隔字符串使同种字符出现在一起

Description:

A string S of lowercase letters is given. We want to partition this string into as many parts as possible so that each letter appears in at most one part, and return a list of integers representing the size of these parts.

Example 1:

Input: S = "ababcbacadefegdehijhklij"
Output: [9,7,8]
Explanation:
The partition is "ababcbaca", "defegde", "hijhklij".
This is a partition so that each letter appears in at most one part.
A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits S into less parts.

Note:

  1. S will have length in range [1, 500].
  2. S will consist of lowercase letters ('a' to 'z') only.

Analysis:

       将字符串拆解为char[], 借助int[]保存每一个字符最后出现的位置,在利用循环从头开始找字符的最后位置对比,比如ababcbacadefegdehijhklij中a的以后位置lastIdx,然后找开始a到最后a中的所有字符的最后位置idx, 如果idx > lastIdx,则更新lastIdx=idx,最后保存这个[firstIdx, lastIdx]的区间长度即为查分字符串的长度。

JAVA CODE

public class Solution {

  public List<Integer> partitionLabels(String S) {
    List<Integer> list = new ArrayList<>();
    if (null == S || S.length() < 1){
      return list;
    }
    //存放每个字母最后出现的位置
    int[] arr = new int[26];
    int len = S.length();
    for (int i = 0; i < len; i++){
      arr[char2Idx(S.charAt(i))] = i;
    }
    int firstIdx = 0;
    while (firstIdx < len){
      int lastIdx = firstIdx;
      for (int i = firstIdx; i < len && i <= lastIdx; i++){
        int idx = arr[char2Idx(S.charAt(i))];
        if (idx > lastIdx){
          lastIdx = idx;
        }
      }
      list.add(lastIdx - firstIdx + 1);
      firstIdx = lastIdx + 1;
    }
    return list;
  }

  private static int char2Idx(char c){
    return c - 'a';
  }

}

另外,发现一个总结题库的博文分享在这里:https://www.cnblogs.com/grandyang/category/625406.html

上一篇:Python中的时间间隔重叠


下一篇:ISO 8601 Java时间间隔解析