LeetCode算法学习笔记——贪心算法

遵循某种规律,不断贪心的选取当前最优的算法。

1.        已知一些孩子和一些糖果,每个孩子有需求因子g,每个糖果有大小s,当某个糖果的大小s>=某个孩子的需求因子g时,代表该糖果可以满足该孩子;求使用这些糖果,最多可以满足多少孩子?

例如g=[5,10,2,9,15,9];s=[6,1,20,3,8]。最多满足3个孩子。

分析:

尽量用最小的糖果刚好满足孩子,这样可以把较大的糖果留出来满足其他的孩子。

统计满足了的孩子个数child

class Solution
{
public:
	int findContentChildren(std::vector<int>& g, std::vector<int>& s)
	{
		int child = 0, cookies = 0;
		std::sort(g.begin(), g.end());
		std::sort(s.begin(), s.end());
		while (child<g.size() && cookies<s.size())//遍历糖果,如果糖果满足小孩需求,小孩加1。也可以遍历小孩,如果糖果满足需求,糖果加1.
		{
			if (g[child] <= s[cookies])
			{
				child += 1;
			}
			cookies += 1;
		}
		return child;
	}
};

2.        摇摆序列

一个整数序列,如果两个相邻元素的差桥好正负交替出现,则该序列被称为摇摆序列,给定一个随机序列,求这个序列满足摇摆序列定义的最长子序列的长度。

输入[1,7,4,9,2,5],结果为6.

分析:

题目的意思时可以组成的最大长度的摇摆序列。当出现连续上升或下降的子序列时,选择最大或最小的数字作为摇摆序列的元素,即取极值。可以使用状态转移实现。

class Solution
{
public:
  int wiggleMaxLength(std::vector<int> &nums)
  {
    if (nums.size()<2)
    {
      return nums.size();
    }
    static const int BEGIN=0;
    static const int UP=1;
    static const int DOWN=2;
    int STATE=BEGIN;
    int max_length=1;
    for (int i = 1; i < nums.size(); i++)
    {
      switch(STATE)
      {
        case BEGIN:
        if (nums[i-1]==nums[i])
        {
          
        }
        if (nums[i-1]>nums[i])
        {
          STATE=DOWN;
          max_length++;
        }
        if (nums[i-1]<nums[i])
        {
          STATE=UP;
          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;
  }
};

3.        移除k个数字

已知一个使用字符串表示的非负整数num,将num中的k个数字移除,求移除k个数字后,可以获得的最小的可能的新数字。

例如:num=1432219,移除k=3时,最小数为1219

分析:

要获得最小的新数字则最高位的数字要最小,其次是次高位,也就是说当选定一个数作为高位数字时后续出现的比他大的数都可以移除,共移除k次。

先比较再确定是否加进数组中

#include<stdio.h>
#include<vector>
#include<string>
class Solution
{
public:
  std::string removeKdigits(std::string num,int k)
  {
    std::vector<int> S;
    std::string result="";
    for (int i = 0; i < num.length(); i++)
    {
      int number=num[i]-'0';
      while (S.size()!=0&&S.back()>number&&k>0)//当S中数据不为空且S的最后一位数据大于新来的数据且k大于0,则弹出原来S中的最后一位数字。
      {
        S.pop_back();
        k--;
      }
      if (number!=0||S.size()!=0)//当数字不为0或者S中有其他数据时,将数据加入到S中
      {
        S.push_back(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";
  }
    return result;
  }
};

4.        一个数组存储了非负整形数据,数组中的第i个元素代表了可以从数组第i个位置最多向前跳跃a[i]步,已知数组各元素的情况下,求是否可以从数组的第0个位置跳跃到最后一个位置?

 分析: 

用jump表示当前位置,当jump能访问到最后一个位置时则返回true。对于任意位置jump,下一个可以访问的位置是从0到index[jump]。对第一个例子分析,0位上是2,所以可以走到3,1两个位置上,此时比较i+a[i]的大小可以发现走到3位置上可以有更多的选择,于是选择走到3的位置,依此类推。

#include<stdio.h>
#include<vector>
#include<string>
class Solution
{
public:
  bool canJump(std::vector<int>& nums)
  {
    std::vector<int> index;
    for (int i = 0; i < nums.size(); i++)
    {
      index.push_back(i+nums[i]);
    }
    int jump=0;
    int max_index=index[0];
    while (jump<nums.size()&&jump<=max_index)//边界条件:当前所处的位置小于数组长度且不能超过最大可到达的位置
    {
      if (max_index<index[jump])
      {
        max_index=index[jump];
      }
      jump++;
    }
    if (jump==index.size())
    {
      return true;
    }
    return false;
  }
};

 5.        在4的基础上最少需要跳跃多少次?

分析:

在到达某点前若一致不跳跃,发现从该点不能跳到更远的地方,在这之前肯定有次必要的跳跃,因此在无法到达更远的地方时,应该跳到一个可以到达更远位置的位置。

1.        设置current_max_index为当前可以达到的最远位置

2.        设置pre_max_index为位置1到位置i中可以达到的最远距离

3.        设置jump_min为最少跳跃的次数

4.        利用i遍历nums数组,若i超过current_max_index,jump_min加1,current_max_index=pre_max_index,即只要current_max_index能覆盖到的地方,pre只记录最远距离,但不传给current_max_index

5.        遍历过程中,若nums[i]+i更大,则更新pre_max_index,时刻保持pre是位置1到位置i中可以达到的最远距离

#include<stdio.h>
#include<vector>
#include<string>
class Solution
{
public:
  int jump(std::vector<int>& nums)
  {
   if (nums.size()<2)
   {
     return 0;
   }
   int current_max_index=nums[0];
   int pre_max_index=nums[0];
   int jump_min=1;
   for (int i = 1; i < nums.size(); i++)
   {
     if (i>current_max_index)//当前位置无法直接跳到i这个位置,需要辅助跳到pre上,pre是位置1到位置i中可以跳的最远的位置。
     {
       jump_min++;
        current_max_index=pre_max_index;//只要current_max_index能覆盖到的地方,pre只记录最远距离,但不传给current_max_index
     }
     if (pre_max_index<nums[i]+i)
     {
       pre_max_index=nums[i]+i;
     }
   }
   return jump_min;
  }
};

6.        已知在一个平面上有一定数量的气球,平面可以看作一个坐标系,在平面的x轴的不同位置安排弓箭手向y轴方向射箭,弓箭可以向y轴走无穷远,给定气球的宽度xstart<x<xend,问至少需要多少弓箭手,将全部气球打爆。

分析:

对各个气球进行排序,按照气球左端点从小到大进行排序

遍历气球数组,同时维护一个射击区间,在满足当前气球射穿的情况下,尽可能击穿更多的气球,每击穿一个新的气球,更新依次射击区间。

如果新的气球没办法被击穿,增加一名弓箭手

#include<stdio.h>
#include<vector>
#include<algorithm>
bool cmp(const std::pair<int,int>&a,const std::pair<int,int>&b)
{
  return a.first<b.first;
}
class Solution
{
public:
  int findMinArrowShots(std::vector<std::pair<int,int>>&points)
  {
    if (points.size()==0)
    {
      return 0;
    }
    std::sort(points.begin(),points.end(),cmp);
    int shoot_num=1;
    int shoot_begin=points[0].first;
    int shoot_end=points[0].second;
    for (int i = 1; i < points.size(); i++)
    {
      if (points[i].first<=shoot_end)
      {
        shoot_begin=points[i].first;
        if (shoot_end>points[i].second)
        {
          shoot_end=points[i].second;
        }        
      }
      else
      {
        shoot_num++;
        shoot_begin=points[i].first;
        shoot_end=points[i].second;
      }
    }
    return shoot_num;
  }
};
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值