算法基礎知識——貪心策略(二)
目錄:
- 應用實例
- 變態跳臺階【劍指Offer_編程題】
- 牛牛找工作【網易】
- 最大乘積【拼多多】
- 剪繩子【劍指Offer_編程題】
- 最大差值【美團】
- 俄羅斯方塊【網易】
- 分蘋果【網易】
- 迴文序列【網易】
- 六一兒童節【拼多多】
- 保留最大的數【搜狐】
- 末尾0的個數【滴滴】
- 瞌睡【網易】
- gas-station【LeetCode】
- 裁剪網格紙【百度】
- 餐館【滴滴】
一、應用實例:
1、題目描述:一隻青蛙一次可以跳上1級臺階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。int jumpFloorII(int number) {}【劍指Offer_編程題】
- 輸入格式:臺階級數n
- 輸出格式:跳法總數
- 樣例輸入:無
- 樣例輸出:無
示例代碼:
class Solution {
public:
long long jumpFloorII(int number){
long long result = 1;
if(number != 0 && number != 1){
for(int i = 2; i <= number; i++){
result *= 2;
}
}
return result;
}
};
2、題目描述:爲了找到自己滿意的工作,牛牛收集了每種工作的難度和報酬。牛牛選工作的標準是在難度不超過自身能力值的情況下,牛牛選擇報酬最高的工作。在牛牛選定了自己的工作後,牛牛的小夥伴們來找牛牛幫忙選工作,牛牛依然使用自己的標準來幫助小夥伴們。牛牛的小夥伴太多了,於是他只好把這個任務交給了你。【網易】
- 輸入格式:每個輸入包含一個測試用例。每個測試用例的第一行包含兩個正整數,分別表示工作的數量N(N<=100000)和小夥伴的數量M(M<=100000)。接下來的N行每行包含兩個正整數,分別表示該項工作的難度Di(Di<=1000000000)和報酬Pi(Pi<=1000000000)。接下來的一行包含M個正整數,分別表示M個小夥伴的能力值Ai(Ai<=1000000000)。保證不存在兩項工作的報酬相同。
- 輸出格式:對於每個小夥伴,在單獨的一行輸出一個正整數表示他能得到的最高報酬。一個工作可以被多個人選擇。
- 樣例輸入:
- 3 3
- 1 100
- 10 1000
- 1000000000 1001
- 9 10 1000000000
- 樣例輸出:
- 100
- 1000
- 1001
示例代碼:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int MAX_N = 100001;
struct Node{
int difficult;
int pay;
Node(int d, int p):difficult(d), pay(p){};
bool operator<(const Node &n)const{
return difficult < n.difficult;
};
};
struct Person{
int ability;
int index;
Person(int a, int i):ability(a), index(i){};
bool operator<(const Person &p)const{
return ability < p.ability;
};
};
vector<Node> nodeList;
vector<Person> abilityList;
int result[MAX_N];
int main(){
int n, m; //n爲工作數,m爲人數
while(cin >> n >> m){
int di, pi, a;
nodeList.clear();
abilityList.clear();
for(int i = 0; i < n; i++){
cin >> di >> pi;
nodeList.push_back(Node(di, pi));
}
for(int i = 0; i < m; i++){
cin >> a;
abilityList.push_back(Person(a, i));
}
sort(nodeList.begin(), nodeList.end());
sort(abilityList.begin(), abilityList.end());
int maxSalary = 0, index = 0;
for(int i = 0; i < m; i++){
for(int j = index; j < nodeList.size(); j++){
if(nodeList[j].difficult <= abilityList[i].ability){
if(maxSalary < nodeList[j].pay){
maxSalary = nodeList[j].pay;
result[abilityList[i].index] = maxSalary;
}
index++;
}else{
break;
}
}
result[abilityList[i].index] = maxSalary;
}
for(int i = 0; i < m; i++){
cout << result[i] << endl;
}
}
return 0;
}
3、題目描述:給定一個無序數組,包含正數、負數和0,要求從中找出3個數的乘積,使得乘積最大,要求時間複雜度:O(n),空間複雜度:O(1)【拼多多】
- 輸入格式:輸入共2行,第一行包括一個整數n,表示數組長度。第二行爲n個以空格隔開的整數,分別爲A1,A2, … ,An
- 輸出格式:滿足條件的最大乘積
- 樣例輸入:
- 4
- 3 4 1 2
- 樣例輸出:
- 24
示例代碼1:
#include <iostream>
using namespace std;
const long long MAX_INT = 0x7fffffffffffffff;
const long long MIN_INT = -0x7fffffffffffffff;
//兩最大負數,一最大正數,或者三個最大正數,或者最小三個負數
long long pos1;
long long pos2;
long long pos3;
long long negMax1;
long long negMax2;
long long negMin1;
long long negMin2;
long long negMin3;
int main(){
int n;
while(cin >> n){
//flag1表示至少有兩個正數,flag2表示有兩個負數,flag3表示有正數
bool flag1 = false, flag2 = false, flag3 = false;
pos1 = pos2 = pos3 = MIN_INT;
negMax1 = negMax1 = MAX_INT;
negMin1 = negMin2 = negMin3 = MIN_INT;
int inputNumber;
for(int m = 0; m < n; m++){
cin >> inputNumber;
if(inputNumber < 0){
if(inputNumber <= negMax1){
negMax2 = negMax1;
negMax1 = inputNumber;
}else if(inputNumber > negMax1 && inputNumber <= negMax2){
negMax2= inputNumber;
flag2 = true;
}
if(inputNumber >= negMin1){
negMin3 = negMin2;
negMin2 = negMin1;
negMin1 = inputNumber;
}else if(inputNumber < negMin1 && inputNumber >= negMin2){
negMin3 = negMin2;
negMin2 = inputNumber;
}else if(inputNumber < negMin1 && inputNumber < negMin2 && inputNumber > negMin3){
negMin3 = inputNumber;
}
}else if(inputNumber > 0){
if(inputNumber >= pos1){
pos3 = pos2;
pos2 = pos1;
pos1 = inputNumber;
flag3 = true;
}else if(inputNumber < pos1 && inputNumber >= pos2){
pos3 = pos2;
pos2 = inputNumber;
flag1 = true;
}else if(inputNumber < pos1 && inputNumber < pos2 && inputNumber > pos3){
pos3 = inputNumber;
}
}
}
long long result = 1;
if(!flag1){
result = pos1 * negMax1 * negMax2;
}else if(!flag2){
result = pos1 * pos2 * pos3;
}else if(!flag3){
result = negMin1 * negMin2 * negMin3;
}else{
long long result1 = pos1 * pos2 * pos3;
long long result2 = negMax1 * negMax2 * pos1;
result = max(result1, result2);
}
cout << result << endl;
}
return 0;
}
示例代碼2:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<long long> numList;
int main(){
int n;
long long inputNumber;
while(cin >> n){
numList.clear();
for(int i = 0; i < n; i++){
cin >> inputNumber;
numList.push_back(inputNumber);
}
sort(numList.begin(), numList.end());
long long result = 0;
if(numList[n - 1] <= 0){
int i = n - 1;
while(i >= 0 && numList[n - 1] == 0){
i--;
}
if(i >= 2){
result = numList[i] * numList[i - 1] * numList[i - 2];
}
}else{
long long result1 = numList[n - 1] * numList[n - 2] * numList[n - 3];
long long result2 = numList[0] * numList[1] * numList[n - 1];
result = max(result1, result2);
}
cout << result << endl;
}
return 0;
}
4、題目描述:給你一根長度爲n的繩子,請把繩子剪成整數長的m段(m、n都是整數,n>1並且m>1),每段繩子的長度記爲k[0],k[1],...,k[m]。請問k[0]xk[1]x...xk[m]可能的最大乘積是多少?例如,當繩子的長度是8時,我們把它剪成長度分別爲2、3、3的三段,此時得到的最大乘積是18。【劍指Offer_編程題】
- 輸入格式:輸入一個數n,意義見題面。(2 <= n <= 60)
- 輸出格式:輸出答案。
- 樣例輸入:
- 8
- 樣例輸出:
- 18
示例代碼:
class Solution {
public:
int cutRope(int number) {
if(number == 2){
return 1;
}else{
int split = (int)round(sqrt(number));
int result = 1;
int sub = number / split;
int count = number - split * sub;
while(number > 0){
if(count > 0){
result *= (sub + 1);
number -= (sub + 1);
count--;
}else{
result *= sub;
number -= sub;
}
}
return result;
}
}
};
5、題目描述:有一個長爲n的數組A,求滿足0≤a≤b<n的A[b]-A[a]的最大值。給定數組A及它的大小n,請返回最大差值。
int getDis(vector<int> A, int n) {
// write code here
}【美團】
- 輸入格式:數組A以及它的大小n
- 輸出格式:返回最大差值
- 樣例輸入:
- [10,5],2
- 樣例輸出:
- 0
示例代碼:
class LongestDistance {
public:
int getDis(vector<int> A, int n){
vector<int> dp(n); //記錄該元素之前的最小值
vector<int> result(n); //記錄最大差值
dp[0] = A[0];
result[0] = 0;
for(int i = 1; i < n; i++){
if(A[i] >= dp[i - 1]){
result[i] = A[i] - dp[i - 1];
dp[i] = dp[i - 1];
}else{
dp[i] = A[i];
result[i] = 0;
}
}
int maxValue = result[0];
for(int i = 0; i < n; i++){
cout << result[i] << endl;
maxValue = max(maxValue, result[i]);
}
return maxValue;
}
};
6、題目描述:小易有一個古老的遊戲機,上面有着經典的遊戲俄羅斯方塊。因爲它比較古老,所以規則和一般的俄羅斯方塊不同。熒幕上一共有 n 列,每次都會有一個 1 x 1 的方塊隨機落下,在同一列中,後落下的方塊會疊在先前的方塊之上,當一整行方塊都被佔滿時,這一行會被消去,並得到1分。有一天,小易又開了一局遊戲,當玩到第 m 個方塊落下時他覺得太無聊就關掉了,小易希望你告訴他這局遊戲他獲得的分數。【網易】
- 輸入格式:第一行兩個數 n, m,第二行 m 個數,c1, c2, ... , cm , ci 表示第 i 個方塊落在第幾列。其中 1 <= n, m <= 1000, 1 <= ci <= n
- 輸出格式:小易這局遊戲獲得的分數
- 樣例輸入:
- 3 9
- 1 1 2 2 2 3 1 2 3
- 樣例輸出:
- 2
示例代碼:
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n, m;
while(cin >> n >> m){
vector<int> column(n + 1);
int inputNumber;
for(int i = 0; i < m; i++){
cin >> inputNumber;
column[inputNumber]++;
}
int minValue = column[1];
for(int i = 1; i <= n; i++){
minValue = min(minValue, column[i]);
}
cout << minValue << endl;
}
return 0;
}
7、題目描述:n 只奶牛坐在一排,每個奶牛擁有 ai 個蘋果,現在你要在它們之間轉移蘋果,使得最後所有奶牛擁有的蘋果數都相同,每一次,你只能從一隻奶牛身上拿走恰好兩個蘋果到另一個奶牛上,問最少需要移動多少次可以平分蘋果,如果方案不存在輸出 -1。【網易】
- 輸入格式:每個輸入包含一個測試用例。每個測試用例的第一行包含一個整數 n(1 <= n <= 100),接下來的一行包含 n 個整數 ai(1 <= ai <= 100)。
- 輸出格式:輸出一行表示最少需要移動多少次可以平分蘋果,如果方案不存在則輸出 -1。
- 樣例輸入:
- 4
- 7 15 9 5
- 樣例輸出:
- 3
示例代碼:
#include <iostream>
#include <vector>
using namespace std;
vector<int> nodeList;
int main(){
int n;
while(cin >> n){
int inputNumber, total = 0;
for(int i = 0; i < n; i++){
cin >> inputNumber;
total += inputNumber;
nodeList.push_back(inputNumber);
}
int result = 0;
if(total % n != 0){
result = -1;
}else{
int avg = total / n;
bool flag = true;
for(int i = 0; i < n; i++){
if(nodeList[i] > avg){
if((nodeList[i] - avg) % 2 != 0){
result = -1;
break;
}else{
result += (nodeList[i] - avg) / 2;
}
}
}
}
cout << result << endl;
}
return 0;
}
8、題目描述:如果一個數字序列逆置之後跟原序列是一樣的就稱這樣的數字序列爲迴文序列。例如:{1, 2, 1}, {15, 78, 78, 15} , {112} 是迴文序列,{1, 2, 2}, {15, 78, 87, 51} ,{112, 2, 11} 不是迴文序列。現在給出一個數字序列,允許使用一種轉換操作:選擇任意兩個相鄰的數,然後從序列移除這兩個數,並用這兩個數字的和插入到這兩個數之前的位置(只插入一個和)。現在對於所給序列要求出最少需要多少次操作可以將其變成迴文序列。【網易】
- 輸入格式:輸入爲兩行,第一行爲序列長度n ( 1 ≤ n ≤ 50) 第二行爲序列中的n個整數item[i] (1 ≤ item[i] ≤ 1000),以空格分隔。
- 輸出格式:輸出一個數,表示最少需要的轉換次數
- 樣例輸入:
- 4
- 1 1 1 3
- 樣例輸出:
- 2
示例代碼:
#include <iostream>
#include <deque>
using namespace std;
deque<int> myQueue;
int main(){
int n, inputNumber;
while(cin >> n){
for(int i = 0; i < n; i++){
cin >> inputNumber;
myQueue.push_back(inputNumber);
}
int result = 0;
while(!myQueue.empty()){
if(myQueue.size() == 1){
myQueue.pop_back();
continue;
}
if(myQueue.front() == myQueue.back()){
myQueue.pop_back();
myQueue.pop_front();
}else{
if(myQueue.front() > myQueue.back()){
int a = myQueue.back();
myQueue.pop_back();
a += myQueue.back();
myQueue.pop_back();
myQueue.push_back(a);
}else{
int a = myQueue.front();
myQueue.pop_front();
a += myQueue.front();
myQueue.pop_front();
myQueue.push_front(a);
}
result++;
}
}
cout << result << endl;
}
return 0;
}
9、題目描述:六一兒童節,老師帶了很多好喫的巧克力到幼兒園。每塊巧克力j的重量爲w[j],對於每個小朋友i,當他分到的巧克力大小達到h[i] (即w[j]>=h[i]),他纔會上去表演節目。老師的目標是將巧克力分發給孩子們,使得最多的小孩上臺表演。可以保證每個w[i]> 0且不能將多塊巧克力分給一個孩子或將一塊分給多個孩子。【拼多多】
- 輸入格式:第一行:n,表示h數組元素個數。第二行:n個h數組元素。第三行:m,表示w數組元素個數。第四行:m個w數組元素。
- 輸出格式:上臺表演學生人數
- 樣例輸入:
- 3
- 2 2 3
- 2
- 3 1
- 樣例輸出:
- 1
示例代碼:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<double> childList;
vector<double> chocoList;
int main(){
int inputNumber, n, m;
while(cin >> n){
for(int i = 0; i < n; i++){
cin >> inputNumber;
childList.push_back(inputNumber);
}
sort(childList.begin(), childList.end());
cin >> m;
for(int i = 0; i < m; i++){
cin >> inputNumber;
chocoList.push_back(inputNumber);
}
sort(chocoList.begin(), chocoList.end());
int index = 0, result = 0;
for(int i = 0; i < chocoList.size(); i++){
for(int j = index; j < childList.size(); j++){
if(chocoList[i] >= childList[j]){
result++;
index = j + 1;
break;
}
}
}
cout << result << endl;
}
return 0;
}
10、題目描述:給定一個十進制的正整數number,選擇從裏面去掉一部分數字,希望保留下來的數字組成的正整數最大。【搜狐】
- 輸入格式:輸入爲兩行內容,第一行是正整數number,1 ≤ length(number) ≤ 50000。第二行是希望去掉的數字數量cnt 1 ≤ cnt < length(number)。
- 輸出格式:輸出保留下來的結果。
- 樣例輸入:
- 325 1
- 樣例輸出:
- 35
示例代碼:
#include <iostream>
#include <string>
using namespace std;
int main(){
string s;
int n;
while(cin >> s >> n){
bool flag1 = true;
while(n > 0){
if(flag1){
flag1 = false;
for(int i = 0; i < s.size() - 1; i++){
if(s[i] < s[i + 1]){
flag1 = true;
s.erase(s.begin() + i);
n--;
break;
}
}
}else{
s.erase(s.end() - 1);
n--;
}
}
cout << s << endl;
}
return 0;
}
11、題目描述:輸入一個正整數n,求n!(即階乘)末尾有多少個0? 比如: n = 10; n! = 3628800,所以答案爲2【滴滴】
- 輸入格式:輸入爲一行,n(1 ≤ n ≤ 1000)
- 輸出格式:輸出一個整數,即題目所求
- 樣例輸入:
- 10
- 樣例輸出:
- 2
示例代碼1:
#include <iostream>
using namespace std;
int main(){
int n;
while(cin >> n){
int result = 0;
for(int i = 5; i <= n; i += 5){
int tmp = i;
while(tmp % 5 == 0){
result++;
tmp /= 5;
}
}
cout << result << endl;
}
return 0;
}
示例代碼2:
#include <iostream>
using namespace std;
int main(){
int n;
while(cin >> n){
int result = 0;
while(n){
result += n / 5;
n /= 5;
}
cout << result << endl;
}
return 0;
}
12、題目描述:小易覺得高數課太無聊了,決定睡覺。不過他對課上的一些內容挺感興趣,所以希望你在老師講到有趣的部分的時候叫醒他一下。你知道了小易對一堂課每分鐘知識點的感興趣程度,並以分數量化,以及他在這堂課上每分鐘是否會睡着,你可以叫醒他一次,這會使得他在接下來的k分鐘內保持清醒。你需要選擇一種方案最大化小易這堂課聽到的知識點分值。【網易】
- 輸入格式:第一行 n, k (1 <= n, k <= 105) ,表示這堂課持續多少分鐘,以及叫醒小易一次使他能夠保持清醒的時間。第二行 n 個數,a1, a2, ... , an(1 <= ai <= 104) 表示小易對每分鐘知識點的感興趣評分。第三行 n 個數,t1, t2, ... , tn 表示每分鐘小易是否清醒, 1表示清醒。
- 輸出格式:小易這堂課聽到的知識點的最大興趣值。
- 樣例輸入:
- 6 3
- 1 3 5 2 5 4
- 1 1 0 1 0 0
- 樣例輸出:
- 16
示例代碼:
#include <iostream>
#include <vector>
using namespace std;
vector<int> interest;
vector<int> sleep;
int main(){
int n, k;
while(cin >> n >> k){
int inputNum;
interest.clear();
sleep.clear();
for(int i = 0; i < n; i++){
cin >> inputNum;
interest.push_back(inputNum);
}
for(int i = 0; i < n; i++){
cin >> inputNum;
sleep.push_back(inputNum);
}
int result = 0, increaseValue = 0;
for(int i = 0; i <= n - k; i++){
if(sleep[i] == 0 || i == n - k){
int tmp = 0;
for(int j = i; j < i + k; j++){
if(sleep[j] == 0){
tmp += interest[j];
}
}
increaseValue = max(increaseValue, tmp);
}
}
for(int i = 0; i < n; i++){
if(sleep[i] == 1){
result += interest[i];
}
}
cout << result + increaseValue << endl;
}
return 0;
}
13、題目描述:There are N gas stations along a circular route, where the amount of gas at station i is gas[i].You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.Return the starting gas station's index if you can travel around the circuit once, otherwise return -1.
Note: The solution is guaranteed to be unique.
int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
//write code here
}【LeetCode】
- 輸入格式:
- 輸出格式:
- 樣例輸入:
- 樣例輸出:
示例代碼:
class Solution {
public:
int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
int start = 0, end = gas.size() - 1;
int currentGas = gas[end] - cost[end];
while(start < end){
if(currentGas >= 0){
currentGas += gas[start] - cost[start];
start++;
}else{
end--;
currentGas += gas[end] - cost[end];
}
}
if(currentGas >= 0){
return start;
}else{
return -1;
}
}
};
14、題目描述:度度熊有一張網格紙,但是紙上有一些點過的點,每個點都在網格點上,若把網格看成一個座標軸平行於網格線的座標系的話,每個點可以用一對整數x,y來表示。度度熊必須沿着網格線畫一個正方形,使所有點在正方形的內部或者邊界。然後把這個正方形剪下來。問剪掉正方形的最小面積是多少。【百度】
- 輸入格式:第一行一個數n(2≤n≤1000)表示點數,接下來每行一對整數xi,yi(-1e9<=xi,yi<=1e9)表示網格上的點
- 輸出格式:一行輸出最小面積
- 樣例輸入:
- 2
- 0 0
- 0 3
- 樣例輸出:
- 9
示例代碼:
#include <iostream>
using namespace std;
int main(){
int n;
long long x, y;
while(cin >> n){
long long maxX = 0, maxY = 0, minX = 0, minY = 0;
for(int i = 0; i < n; i++){
cin >> x >> y;
if(x > 0){
maxX = max(x, maxX);
}else{
minX = min(x, minX);
}
if(y > 0){
maxY = max(y, maxY);
}else{
minY = min(y, minY);
}
}
long long maxValue = max((maxY - minY), (maxX - minX));
cout << maxValue * maxValue << endl;
}
return 0;
}
15、題目描述:某餐館有n張桌子,每張桌子有一個參數:a 可容納的最大人數; 有m批客人,每批客人有兩個參數:b人數,c預計消費金額。 在不允許拼桌的情況下,請實現一個算法選擇其中一部分客人,使得總預計消費金額最大【滴滴】
- 輸入格式:c輸入包括m+2行。 第一行兩個整數n(1 <= n <= 50000),m(1 <= m <= 50000) 。第二行爲n個參數a,即每個桌子可容納的最大人數,以空格分隔,範圍均在32位int範圍內。 接下來m行,每行兩個參數b,c。分別表示第i批客人的人數和預計消費金額,以空格分隔,範圍均在32位int範圍內。
- 輸出格式:輸出一個整數,表示最大的總預計消費金額
- 樣例輸入:
- 3 5
- 2 4 2
- 1 3
- 3 5
- 3 7
- 5 9
- 1 10
- 樣例輸出:
- 20
示例代碼:
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
struct Node{
int people;
int money;
Node(int p, int m):people(p), money(m){};
bool operator<(const Node &n)const{
if(money == n.money){
return people < n.people;
}
return money < n.money;
};
};
vector<int> tableList;
priority_queue<Node> nodeList;
int CompareAsc(int x, int y){
return x < y;
}
int main(){
int n, m, inputNum, people, money;
while(cin >> n >> m){
tableList.clear();
for(int i = 0; i < n; i++){
cin >> inputNum;
tableList.push_back(inputNum);
}
for(int i = 0; i < m; i++){
cin >> people >> money;
nodeList.push(Node(people, money));
}
sort(tableList.begin(), tableList.end(), CompareAsc);
long long result = 0;
while(tableList.size() > 0 && !nodeList.empty()){
Node node = nodeList.top();
nodeList.pop();
for(int i = 0; i < tableList.size(); i++){
if(tableList[tableList.size() - 1] < node.people){
break;
}
if(tableList[i] >= node.people){
tableList.erase(tableList.begin() + i);
result += node.money;
break;
}
}
}
cout << result << endl;
}
return 0;
}