《五月集训》第四日——贪心算法

本文介绍了贪心算法在LeetCode四道题目中的应用,包括如何分割平衡字符串以获得最大数量的平衡子串,找到使数组严格递增的最少操作次数,求解购买糖果的最小总开销,以及如何用给定字符串构造最多回文串。解题策略涉及字符串处理、数组遍历、排序和哈希表统计等技巧。

前言

这是五月集训的第四天,今天的训练内容是 贪心算法

解题报告

1.力扣1221

原题链接

https://leetcode-cn.com/problems/split-a-string-in-balanced-strings/

题目概述

在一个 平衡字符串 中,‘L’ 和 ‘R’ 字符的数量是相同的。

给你一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串。

注意:分割得到的每个字符串都必须是平衡字符串,且分割得到的平衡字符串是原平衡字符串的连续子串。

返回可以通过分割得到的平衡字符串的 最大数量 。

解题思路

原来的字符串就是满足一定可以拆分成平衡字符串的,于是只要我们每次出现了一个平衡字符串我们就拆一个就可以得到最多的平衡字符串了。只需要记录 LR 的出现次数,每当它们的出现次数相同的时候,说明又组成了一个新的平衡字符串,计数加一,直到遍历完整个字符串就好。

源码剖析

int balancedStringSplit(char * s){
    int i;
    int a=0,b=0,ans=0;
    int x=strlen(s);
    for(i=0;i<x;++i){
        if(s[i]=='L'){
            a++;
        }else b++;
        if(a==b){
            ans++;
        }
    }
    return ans;
}

直接使用一个简单的循环进行遍历就可以了。

2.力扣1827

原题链接

https://leetcode-cn.com/problems/minimum-operations-to-make-the-array-increasing/

题目概述

给你一个整数数组 nums (下标从 0 开始)。每一次操作中,你可以选择数组中一个元素,并将它增加 1 。

比方说,如果 nums = [1,2,3] ,你可以选择增加 nums[1] 得到 nums = [1,3,3] 。
请你返回使 nums 严格递增 的 最少 操作次数。

我们称数组 nums 是 严格递增的 ,当它满足对于所有的 0 <= i < nums.length - 1 都有 nums[i] < nums[i+1] 。一个长度为 1 的数组是严格递增的一种特殊情况。

解题思路

直接使后一个数等于前一个数加一,然后使用后一个数减去前一个数就可以得到操作数了,遍历整个数组,返回总操作数。

源码剖析

int minOperations(int* nums, int numsSize){
    if(numsSize==1){
        return 0;
    }
    int ans=0;
    for(int i=1;i<numsSize;i++){
        if(nums[i]<=nums[i-1]){
            ans=ans+(nums[i-1]-nums[i]+1);
            nums[i]=nums[i-1]+1;
        }
    }
    return ans;
}

只需注意一点,当长度为一的时候也可以满足条件,特别处理一下即可。

3.力扣2144

原题链接

https://leetcode-cn.com/problems/minimum-cost-of-buying-candies-with-discount/

题目概述

一家商店正在打折销售糖果。每购买 两个 糖果,商店会 免费 送一个糖果。

免费送的糖果唯一的限制是:它的价格需要小于等于购买的两个糖果价格的 较小值 。

比方说,总共有 4 个糖果,价格分别为 1 ,2 ,3 和 4 ,一位顾客买了价格为 2 和 3 的糖果,那么他可以免费获得价格为 1 的糖果,但不能获得价格为 4 的糖果。
给你一个下标从 0 开始的整数数组 cost ,其中 cost[i] 表示第 i 个糖果的价格,请你返回获得 所有 糖果的 最小 总开销。

解题思路

如果想要得到最小的开销的话,就需要尽可能的是的免费赠送的糖果的总数额要大,也就可以先对数组进行排序,随后从最贵的开始买,也就自然可以使得免费赠送的糖果的价格总额变高。

源码剖析

int cmp(const void*a,const void*b){
    return *(int*)a-*(int*)b;
}
int minimumCost(int* cost, int costSize){
    qsort(cost,costSize,sizeof(int),cmp);
    int sum=0;
    int i,num=0;
    for(i=costSize-1;i>=0;--i){
        if(num==2){
            num=0;
        }else{
            sum+=cost[i];
            num++;
        }
    }
    return sum;
}

定义了一个计数器 num (优惠计数器),它的作用是,记录下可以得到优惠的那一项,到这一项就可以直接重置计数器,然后开始下一轮的循环,好处是不用担心越界的问题就统计出了所有的优惠项。

4.力扣1400

原题链接

https://leetcode-cn.com/problems/construct-k-palindrome-strings/

题目概述

给你一个字符串 s 和一个整数 k 。请你用 s 字符串中 所有字符 构造 k 个非空 回文串 。

如果你可以用 s 中所有字符构造 k 个回文字符串,那么请你返回 True ,否则返回 False 。

解题思路

每一个字母单独都可以组成一个回文串,所以 k 最大只能是字符串长度,接下来统计最少要组成的回文串的个数,也就是统计出在里面出现了奇数次的字母,每一个出现了奇数次的字字母都需要位于回文串的中心位置,也就是至少需要一个多一个回文串。统计每个字母出现了多少次可以使用哈希表。

源码剖析

bool canConstruct(char * s, int k){
    int hash[26]={0};
    int x = strlen(s);
    int i,num=0;
    for(i=0;i<x;++i){
        hash[s[i] - 'a']++;        //97是'a'的ASCII码
    }
    for(i=0;i<26;++i){
        if(hash[i]&1){
            num++;
        }
    }
    if(k>=num&&k<=x){
        return true;
    }else{
        return false;
    }
}

首先构建一个哈希表,统计一下每个字母出现的次数,然后遍历哈希表,统计出哈希表中的奇数总数,也就是 k 的最小值了。尤其需要注意的一点是,strlen()语句是非常消耗时间的,不可以写在 for()的判断语句中,否则会使得每次循环都计算一次,相当消耗时间,建议写在最前面用一个变量储存好其值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值