Leetcode学习之贪心算法(1)

开宗明义:本系列基于小象学院林沐老师课程《面试算法 LeetCode 刷题班》,刷题小白,旨在理解和交流,重在记录,望各位大牛指点!


Leetcode学习之贪心算法(1)


文章目录

    • 1、贪心法找钱
    • 2、分糖果(排序、贪心) Leetcode 455.
    • 3、摇摆序列(贪心) Leetcode 376.
    • 4、移除K个数字(栈、贪心) Leetcode 402.


1、贪心法找钱

贪心法遵循某种规律,不断贪心的选取当前最优策略的算法设计方法
成立条件当前最优解为全局最优解
问题描述:有1元、2元、5元、10元、20元、50元、100元的钞票有无穷张。现使用这些钞票支付x元,最少需要多少张?
测试代码

#include 
#include 


int main() {
	const int RMB[] = { 100,50,20,10,5,2,1 };//人民币面额,这边需要排序,从大到小
	const int num = 7;//7种面额

	int x = 628;//用人民币最少多少张,组成x?
	int count = 0;
	for (int i = 0; i < num; i++) {
		int use = x / RMB[i];//需要面额为RMB[i]的use张
		count += use;//总计增加use张
		x = x - RMB[i] * use;//将总额减去使用RMB[i]已组成的金额
		printf("需要面额为%d的%d张,", RMB[i], use);
		printf("剩余需要支付RMB :%d\n", x);
	}
	printf("总共需要 %d 张", count);
	system("pause");
	return 0;
}

效果图
Leetcode学习之贪心算法(1)_第1张图片


2、分糖果(排序、贪心) Leetcode 455.

题目来源 L e e t c o d e   455.   A s s i g n   C o o k i e s Leetcode \ 455.\ Assign \ Cookies Leetcode 455. Assign Cookies
题目描述:已知一些孩子和一些糖果,每个孩子的需求因子为 g g g,每个有个大小 s s s。当某个糖果的大小 s s s>=某个孩子的需求因子 g g g的时候,代表该糖果可以满足孩子,求这些糖果,最多能满足几个孩子?(每个孩子最多只能用一个糖果满足)Leetcode学习之贪心算法(1)_第2张图片
思路

  1. 当某个孩子可以被多个糖果满足时,是否优先使用某个糖果满足孩子?
  2. 当某个糖果可以满足多个孩子,是否需要优先满足某个孩子?

所以某个孩子可以用小的糖果满足,则没必要用更大的糖果满足!所以优先从需求因子小的孩子尝试!
步骤

  1. 对需求因子数组 g g g与糖果大小数组 s s s进行从小到大的排序
  2. 按照从小到大的顺序使用糖果是否满足某个孩子,每个糖果只尝试一次尝试成功,则换下一个孩子尝试,直到没有更多的孩子或者没有更多的糖果,循环结束(无论失败或者成功,每个糖果只尝试一次,cookie向后移动)
    Leetcode学习之贪心算法(1)_第3张图片
    测试代码
#include 
#include 
#include 
#include 

using namespace std;

class Solution {
public:
	int findContentChildren(vector<int>& g, vector<int> & s) {
		sort(g.begin(), g.end());//对孩子的需求因子g与糖果大小s两组数进行排序
		sort(s.begin(), s.end());
		int child = 0;
		int cookie = 0;//child代表已经满足了几个孩子。cookle代表尝试了几个糖果
		while (child < g.size() && cookie < s.size())//当孩子的满足因子和糖果的大小都没有尝试完
		{
			if (g[child] < s[cookie]) {
				child++;//糖果满足了孩子,孩子的child指针向后移动
			}
			cookie++;//无论失败或者成功,每个糖果只尝试一次,cookie向后移动
		}
		return child;//最终child即为满足的孩子个数
	}
};

int main() {
	Solution solve;
	vector<int> g;
	vector<int> s;
	g.push_back(5);
	g.push_back(10);
	g.push_back(2);
	g.push_back(9);
	g.push_back(15);
	g.push_back(9);
	s.push_back(6);
	s.push_back(1);
	s.push_back(20);
	s.push_back(3);
	s.push_back(8);
	printf("%d\n", solve.findContentChildren(g, s));
	system("pause");
	return 0;
}

效果图
Leetcode学习之贪心算法(1)_第4张图片


3、摇摆序列(贪心) Leetcode 376.

题目来源: L e e t c o d e   376.   W i g g l e   S u b s e q u e n c e Leetcode \ 376. \ Wiggle \ Subsequence Leetcode 376. Wiggle Subsequence
题目描述:一个整数序列,如果两个相邻元素的差恰好正负(负正)交替出现,则该序列称为摇摆序列。一个小于2个序列直接称为摇摆序列。给一个随机序列,求这个序列满足摇摆序列定义的最长子序列长度
要求描述
Leetcode学习之贪心算法(1)_第5张图片分析Leetcode学习之贪心算法(1)_第6张图片
思路当序列有一段连续的递增或者递减时,为形成摇摆子序列,保留这段连续的递增或递减的首尾元素,这样更可能使得尾部后一个元素成为摇摆序列的下一个元素
Leetcode学习之贪心算法(1)_第7张图片

测试代码:

#include 
#include 
#include 
#include 

using namespace std;

class Solution {
public:
	int wiggleMaxLength(vector<int> &nums) {
		if (nums.size() < 2) {
			return nums.size();//序列个数小于2时,直接为摇摆序列
		}
		static const int begin = 0;
		static const int up = 1;
		static const int down = 2;//扫描时三种状态

		int state = begin;
		int max_length = 1;//摇摆序列的最大长度至少为1
		//从第二个元素开始扫描
		for (int i = 1; i < nums.size(); i++) {
			switch (state) {
			case begin:
				if (nums[i] > nums[i - 1]) {
					state = up;
					max_length++;
				}
				else if(nums[i-1]>nums[i]){
					state = down;
					max_length++;
				}
				break;
			case up:
				if (nums[i - 1] > nums[i]) {
					state = down;
					max_length++;
				}
				break;
			case down:
				if (nums[i - 1] < nums[i]) {
					state = up;
					max_length++;
				}
				break;
			}
		}
		return max_length;
	}
};

int main() {
	Solution solve;
	vector<int> g;
	g.push_back(1);
	g.push_back(17);
	g.push_back(5);
	g.push_back(10);
	g.push_back(13);
	g.push_back(15);
	g.push_back(10);
	g.push_back(5);
	g.push_back(16);
	g.push_back(8);
	printf("%d\n", solve.wiggleMaxLength(g));
	system("pause");
	return 0;
}

效果图
Leetcode学习之贪心算法(1)_第8张图片


4、移除K个数字(栈、贪心) Leetcode 402.

题目来源: L e e t c o d e   402.   R e m o v e   K   D i g i t s Leetcode \ 402. \ Remove \ K \ Digits Leetcode 402. Remove K Digits
题目描述:已知一个使用字符串表示的非负整数num,将num中的k个数字移除,求移除这k个数字后,可以获得最小的可能的新数字。
要求描述: 输入的num不会以任何数量的0字符开头,且字符长度<=10002,字符长度大于k。
Leetcode学习之贪心算法(1)_第9张图片
思路
Leetcode学习之贪心算法(1)_第10张图片使用栈存储最终结果或者删除工作,从高位向低位遍历num,如果遍历的数字大于栈顶元素,则将该数字push入栈,如果小于栈顶元素,则将原来的栈顶元素pop出栈,直到栈为空或者不能再删除数字(k=0)或者栈顶元素小于当前元素为止
Leetcode学习之贪心算法(1)_第11张图片
思考
Leetcode学习之贪心算法(1)_第12张图片
测试代码:

#include 
#include 
#include 
#include 

using namespace std;

class Solution {
public:
	string removeKdigits(string num, int k) {
		vector<int> s;//使用vector作为栈,因为vector可以遍历
		string result = "";//存储最终结果的字符串

		for (int i = 0; i < num.length(); i++) {
			int number = num[i] - '0';//将字符型num转化成整数使用

			while (s.size() != 0 && s[s.size() - 1] > number && k > 0) {//当栈不空且栈顶元素大于数number且仍然可以删除数字
				s.pop_back();//弹出栈顶元素
				k--;
			}

			if (number != 0 || s.size() != 0) {  //往栈里添元素,如100
				s.push_back(number);//将数字number压入栈
			}

		}


		while (s.size() != 0 && k > 0) {//如果栈不为空且仍可以删数字
			s.pop_back();
			k--;
		}

		for (int i = 0; i < s.size(); i++) {
			result.append(1, '0' + s[i]);//整数转字符
		}

		if (result == "") {
			result = "0";//如果result为空,result为0
		}
		return result;
	}
};

int main() {
	Solution solve;
	string result = solve.removeKdigits("1432219", 3);
	printf("%s\n", result.c_str());
	string result2 = solve.removeKdigits("100200", 1);
	printf("%s\n", result2.c_str());
	system("pause");
	return 0;
}

效果图
Leetcode学习之贪心算法(1)_第13张图片

你可能感兴趣的:(Leetcode)