[algorithm] greedy algorithm: LeetCode 135 distributes candy and LeetCode 860 lemonade change

LeetCode 135: distribute candy

(difficult)

subject

describe
The teacher wants to distribute candy to the children. There are N children standing in a straight line. The teacher will score each child in advance according to their performance.
You need to help the teacher distribute candy to these children according to the following requirements:
Each child is assigned at least one candy.
Children with higher scores must get more candy than their neighbors on both sides.
So how many candies does the teacher need to prepare at least?

Example 1:
Input: [1,0,2]
Output: 5
Explanation: you can distribute 2, 1 and 2 sweets to the three children respectively.

Example 2:
Input: [1,2,2]
Output: 4
Explanation: you can distribute 1, 2 and 1 candy to the three children respectively.
The third child received only one candy, which met the above two conditions

thinking

This question requires that "children with higher scores must get more candy than their neighbors on both sides", and what is the minimum amount of candy to be distributed. When I make a preliminary verification of this question, the question actually implies a layer of meaning, that is, when two adjacent children have equal scores, they can tolerate the situation that the other party has more candy than themselves, But it is intolerable that those who score lower than themselves have more candy than themselves.

When I was doing this problem, I thought of an abstraction of a broken line graph, that is, the ordinate represents the number of sweets, and the abscissa represents the child's number. The child's number corresponds to the child's score. The score is higher than that of the children on the left and right sides. In this graph, it should be on the left and right points, including the slope peak of their own point, and the final ordinate sequence is an array of candy distribution quantity, If such an ordinate sequence is updated, because there is at least one candy for each child, we first initialize an array with each element of 1, and then update the array from left to right to ensure that if the child on the right has a high score, the number of candy is 1 larger than that of the child on the left; Then update the array from right to left to ensure that if the child on the left has a high score, the number of sweets will be 1 larger than that of the child on the right. However, since the array has been updated once from left to right, it may meet the requirement of 1 larger number of sweets, so it can be compared and judged.

When I was doing this problem, I made a mistake. Although I wanted to update it from left to right first, and then from right to left, when I implemented it, the mistake was written as shown in the following figure. This will cause the result group of result candy to be [1, 2, 2], but actually it should be [1, 2, 3]. The reason for this is, At that time, I only updated one direction.

realization

public class TX9 Distribute candy {
    public int candy(int[] ratings) {
        int candySum = 0;
        int[] result = new int[ratings.length];
        Arrays.fill(result, 1);

        //Left - > right
        for (int i = 0; i < ratings.length - 1; i++) {
            if (ratings[i + 1] > ratings[i]) { //Right big
                result[i + 1] = result[i] + 1;
            }
        }

        //Right - > left
        for (int i = ratings.length - 1; i > 0; i--) {
            if (ratings[i - 1] > ratings[i]) { //Left big
                result[i - 1] = Math.max(result[i] + 1, result[i - 1]);
            }
        }

        for (int i = 0; i < result.length; i++) {
            candySum += result[i];
        }

        return candySum;
    }

    public static void main(String[] args) {
        TX9 Distribute candy s = new TX9 Distribute candy();
        System.out.println("s.candy(new int[]{1, 0, 2}) = " + s.candy(new int[]{1, 0, 2}));
        System.out.println("s.candy(new int[]{1, 2, 87, 87, 87, 2, 1}) = " + s.candy(new int[]{1, 2, 87, 87, 87, 2, 1}));
    }
}

LeetCode 860: Lemonade change

(simple)

subject

describe
At the lemonade stand, each glass of lemonade costs $5. Customers line up to buy your products (in the order of bill payment) one cup at a time.
Each customer buys only one glass of lemonade and pays you $5, $10 or $20. You must give each customer the correct change, that is, the net transaction is that each customer pays you $5.
Note that you don't have any change at first.
Give you an integer array bills, where bills[i] is the bill paid by the ith customer. If you can give each customer the correct change, return true, otherwise return false.

Example 1
Input: bills = [5,5,5,10,20]
Output: true
Explanation:
For the first three customers, we charge three five dollar bills in sequence.
At the fourth customer, we charge a $10 bill and return $5.
At the fifth customer, we returned a $10 bill and a $5 bill.
Since all customers get the correct change, we output true.

Example 2:
Input: bills = [5,5,10,10,20]
Output: false
Explanation:
At the first two customers, we charge two five dollar bills in order.
For the next two customers, we charge a $10 bill and return $5.
For the last customer, we can't return $15 because we only have two $10 bills.
Not every customer gets the correct change, so the answer is false.

Example 3:
Input: bills = [5,5,10]
Output: true

Example 4:
Input: bills = [10,10]
Output: false

thinking

This problem is a greedy algorithm problem that can be solved by thinking about life logic. It belongs to the entry level. There are only three kinds of array element values, namely 5, 10 and 20, and 5 yuan is charged each time, and the extra change is given. Therefore, 5 is the smallest unit, 20 is the largest unit, and the smallest unit 5 can be used to give 10 yuan change and 20 yuan change, while the largest unit 20 can't give any payment change, And 10 yuan can only give 20 yuan change. Therefore, in line with the greedy idea, 5 is the element with the most applicable conditions, and 10 is the element with the second most applicable conditions. Therefore, we should consume 10 first. If we still need change, we can consume 5 with more applicable conditions. This is the greedy idea.

Just traverse the array once and dynamically record the current number of 5 and 10. If the customer gives 5 yuan, you don't need change and directly increase the inventory of 5. If the customer gives 10 yuan, check whether there is 5 yuan. If there is 5 yuan, the inventory of 5 will be reduced by 1 and the inventory of 10 will be increased by 1. If the payment is 20 yuan, if there is 10, you should consume a 10 first and then consume 5 yuan. If there is no 10, You can only consume 5 yuan more applicable.

realization

public class TX10 Lemonade change {
    public boolean lemonadeChange(int[] bills) {
        if (bills == null || bills.length == 0) {
            return false;
        }

        int fiveNum = 0;
        int tenNum = 0;
        //There is no need to make statistics for 20 yuan, because the maximum is 20, which can't be used for change
        for (int i = 0; i < bills.length; i++) {
            if (bills[i] == 5) {
                fiveNum++;
            } else if (bills[i] == 10) {
                //I want five yuan
                if (fiveNum > 0) {
                    fiveNum--;
                    tenNum++;
                } else {
                    return false;
                }
            } else { //When you pay 20 yuan
                //Want to find 15 yuan (1:5 + 5 + 5, 2:10 + 5)
                //Give 10 change first
                if (tenNum > 0 && fiveNum > 0) {
                    tenNum--;
                    fiveNum--;
                } else if (fiveNum > 3) {
                    fiveNum -= 3;
                } else {
                    return false;
                }
            }
        }
        return true;
    }
}

Tags: Algorithm data structure leetcode

Posted on Mon, 11 Oct 2021 19:18:01 -0400 by anon_login_001