leetcode 135. Candy 三种解法

题意

给每个孩子分糖果,如果这个孩子的rating比相邻的孩子高,那么他分到的糖果就要比他多,求最少需要多少糖果。

There are N children standing in a line. Each child is assigned a rating value.

You are giving candies to these children subjected to the following requirements:

  • Each child must have at least one candy.
  • Children with a higher rating get more candies than their neighbors.

What is the minimum candies you must give?

Example 1:

Input: [1,0,2]
Output: 5
Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively.

Example 2:

Input: [1,2,2]
Output: 4
Explanation: You can allocate to the first, second and third child with 1, 2, 1 candies respectively.
             The third child gets 1 candy because it satisfies the above two conditions.

test cases

[3,2,1,1,2,4,3,2,1,0,0]
[1,0,2]
[1,0,2,2,3,4,5,6,7,7,8,9,0,1,2,3,2,1,1,2,1,0]
[3,2,1,1,2,3,2,2,3,4,2,2,1]
[]
[1,2,2,2,1,1,3,1,2,10,20,19,18,17,16,15,4,3,2,1,2,2,1,1,0,1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1,0,10]
[1]
[0]

解1 只遍历一遍即得出结果

时间复杂度O(N)

[3,2,1,1,2,4,3,2,1,0,0]对这个用例,分法应该为:

[3,2,1,1,2,5,4,3,2,1,1]

过程为:

[1]

[2,1]

[3,2,1]

[3,2,1,1]

[3,2,1,1,2]

[3,2,1,1,2,3]

[3,2,1,1,2,3,1]

[3,2,1,1,2,3,2,1]

[3,2,1,1,2,4,3,2,1]

[3,2,1,1,2,5,4,3,2,1]

[3,2,1,1,2,5,4,3,2,1,1]

思路:维护3个变量:当前高度、前最大高度、当前台阶高度。

如果比前一个孩子分高,

​ 如果是第一次上升,那么当前台阶高度=2,

​ 如果不是第一次上升,那么当前台阶高度++;

​ 结果加上当前台阶高度。

如果比前一个孩子分低,

​ 如果不是第一次下降,那么台阶高度++;

​ 如果是第一次下降,那么台阶高度=1;

​ 结果加上 high < maxHigh ? high : maxHigh + 1;

如果相等,

​ 与前面隔断。

讲不清楚,也很复杂,直接上代码

    // Runtime: 2 ms, faster than 95.29% of Java online submissions for Candy.
    //Memory Usage: 39.7 MB, less than 16.42% of Java online submissions for Candy.
    public int candy(int[] ratings) {
        if (ratings == null || ratings.length == 0)
            return 0;
        int prev = ratings[0];
        int sum = 1;
        int level = 1;
        int high = 1;
        int maxHigh = 1;
        for (int i = 1; i < ratings.length; i++) {
            if (ratings[i] > prev) {
                if (level++ == 1)
                    high = 2;
                else
                    high++;
                maxHigh = high;
                sum += level;
            } else if (ratings[i] < prev) {
                if (level == 1) {
                    high++;
                } else {
                    level = 1;
                    high = 1;
                }
                sum += high < maxHigh ? high : maxHigh + 1;
                if (high == maxHigh)
                    high++;
                maxHigh = Math.max(high, maxHigh);
            } else {
                level = 1;
                high = 1;
                maxHigh = 1;
                sum += 1;
            }
            prev = ratings[i];
        }
        return sum;
    }

解2

因为有排序,时间复杂度O(NlogN(N))

贪心,思路就比较简单了,实现也简单,只是效率低一些。

永远找出分数最小的一个,如果比邻居高,那么糖果就要比高的邻居还要高,并且取最大值,分配。

根据这个思路,我很快就实现了,结果花费了20ms,花费了解1十倍的时间。

    // 贪心
    // Runtime: 20 ms, faster than 11.77% of Java online submissions for Candy.
    //Memory Usage: 45.7 MB, less than 16.42% of Java online submissions for Candy.
    public int candy(int[] ratings) {
        if (ratings == null || ratings.length == 0)
            return 0;
        Map<Integer, List<Integer>> indexes = new HashMap<>();
        int[] candies = new int[ratings.length];
        for (int i = 0; i < ratings.length; i++) {
            indexes.putIfAbsent(ratings[i], new ArrayList<>());
            indexes.get(ratings[i]).add(i);
        }
        int[] sorted = Arrays.copyOf(ratings, ratings.length);
        Arrays.sort(sorted);
        int sum = 0;
        for (int i = 0; i < sorted.length; i++) {
            if (i > 0 && sorted[i] == sorted[i - 1])
                continue;
            for (Integer j : indexes.get(sorted[i])) {
                if (j > 0 && ratings[j] > ratings[j - 1])
                    candies[j] = candies[j - 1] + 1;
                if (j < ratings.length - 1 && ratings[j] > ratings[j + 1])
                    candies[j] = Math.max(candies[j], candies[j + 1] + 1);
                if (candies[j] == 0)
                    candies[j] = 1;
                sum += candies[j];
            }
        }
        return sum;
    }

解3 遍历两次,从左往右一次,从右往左依一次

时间复杂度O(N)

用两种方法做了之后网上看了别人的解法,发现了这种思路简单,容易实现,而且效率也高的做法。

非常赞,其实刚看到这道题的时候就想到了,但是当时就想着只遍历一次,然后在解1的路上越走越远,好在还是做出来了,但是不如解3的方法。

    // Runtime: 1 ms, faster than 100.00% of Java online submissions for Candy.
    //Memory Usage: 39.7 MB, less than 16.42% of Java online submissions for Candy.
    public int candy3(int[] ratings) {
        int[] extraCandies = new int[ratings.length];

        for (int i = 1; i < ratings.length; i++) {
            if (ratings[i] > ratings[i - 1]) {
                extraCandies[i] = extraCandies[i - 1] + 1;
            }
        }
        for (int i = ratings.length - 2; i >= 0; i--) {
            if (ratings[i + 1] < ratings[i])
                extraCandies[i] = Math.max(extraCandies[i], extraCandies[i + 1] + 1);
        }
        int sum = 0;
        for (int extraCandy : extraCandies) {
            sum += extraCandy;
        }
        return sum + ratings.length;
    }

版权声明:本文为he25819原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。