贪心,初次见面礼:手套问题

题目: 

在地下室里放着n种颜色的手套,手套分左右手,但是每种颜色的左右手手套个数不一定相同。A先生现在要出门,所以他要去地下室选手套。但是昏暗的灯光让他无法分辨手套的颜色,只能分辨出左右手。所以他会多拿一些手套,然后选出一双颜色相同的左右手手套。现在的问题是,他至少要拿多少只手套(左手加右手),才能保证一定能选出一双颜色相同的手套。

给定颜色种数n(1≤n≤13),同时给定两个长度为n的数组left,right,分别代表每种颜色左右手手套的数量。数据保证左右的手套总数均不超过26,且一定存在至少一种合法方案。

思路:

此题用到了贪心算法,对我而言可能是一个比较新的算法。之前可能接触到过,但是印象不太深。

我们来看这道题的解法:

有n种颜色,并且手套分左右手,我们最后要能得到一双完整的手套(左手+右手,并且颜色相同)。

保证成对存在的手套且每个颜色都覆盖的话,

对于非0(递增)序列a1,a2...an,要想最终取值覆盖每一个种类 n =sum(a1...an) -a1 +1(也就是总数减去最小值之后加一) 

为什么会是这样呢?(只能通过举例子了)

倘若我们有两样水果放在一个黑箱里,苹果4个,橙子7个。我们至少要拿几个,才能保证两样水果个有一个呢?

运气好的话,我们那两个,苹果橙子各一个。要是运气不好呢?拿4个吗?万一全是橙子呢?那怎么办呢?我们先拿7个,这可能有好几种情况,但是最糟糕的情况就是我们全拿的是橙子,因此我们在拿一个肯定是苹果。回到我们这个题目,可以理解一下得到所有颜色需要那多少个手套。

但是注意,题目中说明,某种颜色的手套可能只有左手或者只有右手。,所以呢?为了避免不匹配,我们要假设全这些手套,全部拿走。到这里我们的思路就成型了

总结: 

//求最少的的手套数量,并且保证至少有一个是成对的。
    //假想理想的情况
    //把左手没有或者右手没有的手套全部拿走,剩下的手套必定能成对。
    //对于成对的手套要想最终取值覆盖每一个种类 
    //求出了左右手能覆盖必定成对手套的所有颜色的数量,选取最小的那个
    //我们求出的方案就是    全部不能成套的手套+左右手必定能成对的数量且覆盖所有颜色的最小的那个+另外一边的随便一只手套

代码实现 :


    int findMinimum(int n, vector<int> left, vector<int> right) {
       
        int sum=0;
        int left_sum=0;
        int right_sum=0;
        int left_min=INT_MAX;
        int right_min=INT_MAX;
        for(int i=0;i<n;++i)
        {
            if(left[i]==0||right[i]==0)
            {
                sum+=(left[i]+right[i]);
            }
            else
            {
                left_sum+=left[i];
                right_sum+=right[i];
                left_min=left_min>left[i]?left[i]:left_min;
                right_min=right_min>right[i]?right[i]:right_min;
            }
        }
        return sum+min((left_sum-left_min+1),(right_sum-right_min+1))+1;
    }

题目:两地调度

公司计划面试 2N 人。第 i 人飞往 A 市的费用为 costs[i][0],飞往 B 市的费用为 costs[i][1]。

返回将每个人都飞到某座城市的最低费用,要求每个城市都有 N 人抵达。

输入输出:

输入:[[10,20],[30,200],[400,50],[30,20]]
输出:110
解释:
第一个人去 A 市,费用为 10。
第二个人去 A 市,费用为 30。
第三个人去 B 市,费用为 50。
第四个人去 B 市,费用为 20。

最低总费用为 10 + 30 + 50 + 20 = 110,每个城市都有一半的人在面试。

思路:

我们不能按照每个城市每个人的排序进行选择,因为可能会有一些重叠。我们可以用数组组织每个人去A市的费用减去去B市的费用。两者相差越大,其结果越小。我们对此进行排序。前n个去A市,后面的去B市。将此思路进行扩展,写出代码。

代码:

 
 int twoCitySchedCost(vector<vector<int>>& costs) {
          if(costs.empty())
            return 0;
          
          int ret=0;
          vector<int> arr;
          for(int i=0;i<costs.size();++i)
          {
              ret+=costs[i][0]+costs[i][1];
              arr.push_back(costs[i][0]-costs[i][1]);
          }
          sort(arr.begin(),arr.end());
           for(int i=costs.size()-1;i>=0;--i)
           {
               if(i>=costs.size()/2)
               ret-=arr[i];
               else
                ret+=arr[i];    
           }
         return ret/2;
           
    }



int twoCitySchedCost(vector<vector<int>>& costs) {
          if(costs.empty())
            return 0;
          //假设所有人全去A市
          //每个人去A 市的费用减去去B是的费用,排列好顺序(从小到大)
          //该值越大说明那个人去A市花费越贵,而去B市比较便宜
          int ret=0;
          vector<int> arr;
          for(int i=0;i<costs.size();++i)
          {
              ret+=costs[i][0];
              arr.push_back(costs[i][0]-costs[i][1]);
          }
          sort(arr.begin(),arr.end());
           for(int i=costs.size()-1;i>=costs.size()/2;--i)
           {
               ret-=arr[i];
           }
         return ret;
           
    }

题目:玩筹码

数轴上放置了一些筹码,每个筹码的位置存在数组 chips 当中。

你可以对 任何筹码 执行下面两种操作之一(不限操作次数,0 次也可以):

将第 i 个筹码向左或者右移动 2 个单位,代价为 0。
将第 i 个筹码向左或者右移动 1 个单位,代价为 1。
最开始的时候,同一位置上也可能放着两个或者更多的筹码。

返回将所有筹码移动到同一位置(任意位置)上所需要的最小代价。

 输入输出:

 输入:chips = [2,2,2,3,3]

解释:第1、2、3个筹码放在二号位置,第4、5个筹码放在三号位置

输出:2 解释:第四和第五个筹码移动到位置二的代价都是 1,所以最小总代价为 2。

思路:

将第 i 个筹码向左或者右移动 2 个单位,代价为 0。我们可以用这条规则,将奇数位置的筹码移到1号位置,代价为0;将偶数位置的筹码移到2号位置,代价为0;
将第 i 个筹码向左或者右移动 1 个单位,代价为 1。我们可以将一号位置的筹码移到二号位置,代价为一号筹码个数。

我们可以将二号位置的筹码移到一号位置,代码为二号筹码个数。最小代价,就是选出最小的那个数。

代码:

int minCostToMoveChips(vector<int>& chips) {
        if(chips.empty())
         return 0;
         int evenCount=0;
         int oddCount=0;
         for(int i=0;i<chips.size();++i)
         {
             if(chips[i]%2==0)
             {
                 evenCount++;
             }
             else
             {
                 oddCount++;
             }
         }
         return min(evenCount,oddCount);

    }

 

手套问题:

链接:https://www.nowcoder.com/questionTerminal/365d5722fff640a0b6684391153e58d8

两地调度问题:

链接:https://leetcode-cn.com/problems/two-city-scheduling

玩筹码问题:

链接:https://leetcode-cn.com/problems/play-with-chips

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值