題目:https://oj.leetcode.com/problems/candy/
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?
題目意思是一羣小孩站成一列,每個小孩有一個值rating,給小孩們分發糖果,需要滿足兩個條件:1,每個小孩至少有一個糖果
2,rating比較高的小孩要比他旁邊的小孩拿到的糖果多
剛開始還以爲是和素數環一樣的問題...仔細看了看發現沒有思路...菜鳥渣渣不會做==
所以上網查了別人的解題報告,發現了一個巧妙的解法,只需要兩遍遍歷數組,時間複雜度爲O(N)就可以解決了。
解題思路:
1,首先給數組每個元素賦值爲1
vector<int> candyNum(ratings.size(),1);
2,先向右遍歷一遍數組,如果後面的rating比較大就給後面的小孩多分配一個糖果;
3,再向左遍歷一遍數組,如果前面的rating比較大,令cur = 後面的小孩的糖果數 + 1,如果cur比之前的candyNum[i]要大,則將candyNum[I]的值賦值爲cur。
4,然後再把所有值相加即可。
但是有人會問,爲什麼這樣兩次掃描就能保證比兩邊都大?
其實仔細想想就可以發現,第一次掃描找出了向右的相鄰的最長上升子序列;而第二次掃描找出的是向左的相鄰最長上升子序列而且和之前的向右掃描時候的賦值做了比較,得到的是最大的那個結果。所以這樣的解法是能夠保證rating大的得到的糖果比兩邊都多,而且糖果總數最少。
我覺得這個解題思路還挺巧妙的,如果以後遇到這種需要考慮和左右數據相關的題目可以嘗試使用這種思路考慮一下。
AC代碼:
class Solution {
public:
int candy(vector<int> &ratings) {
int len = ratings.size();
vector<int> candyNum(len,1);
for(int i = 1;i < len;i++){
if(ratings[i] > ratings[i - 1]){
candyNum[i] = candyNum[i - 1] + 1;
}
}
//res爲返回值,因爲第二遍掃描時每一個小孩的糖果數已經確定所以可以在掃描的同時計算出結果
int res = candyNum[len - 1];
int cur;
for(int i = len - 2;i >= 0;i--){
if(ratings[i] > ratings[i + 1]){
cur = candyNum[i + 1] + 1;
//取向左和向右掃描時比較大的值作爲小孩最後得到的糖果數
candyNum[i] = cur > candyNum[i] ? cur : candyNum[i];
}
res += candyNum[i];
}
return res;
}
//整個解題思路是在於:先向右掃描一遍數組,如果後面的rating比較大就比前面的小孩多分配一個糖果
//再向左掃描一遍數組,如果前面的rating比較大就比後面的小孩多分配一個糖果
//這樣能保證小孩是在處於最長上升序列中的賦值
};