算法入门-贪心1

第八部分:贪心

409.最长回文串(简单)

给定一个包含大写字母和小写字母的字符串 s ,返回通过这些字母构造成的最长的回文串 的长度。

在构造过程中,请注意 区分大小写 。比如 "Aa" 不能当做一个回文字符串。

示例 1:

输入:s = "abccccdd"
输出:7
解释:
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。

示例 2:

输入:s = "a"
输出:1
解释:可以构造的最长回文串是"a",它的长度是 1。

第一种思路:

看到这种需要统计数量的,不自然的会想到使用字典的数据结构,按照这种思路,我考虑如下:

  1. 空字符串检查

  • 首先检查输入字符串 s 是否为空。如果为空,直接返回0,因为没有字符可以构成回文串。

  1. 字符计数

  • 使用一个 HashMap 来统计字符串中每个字符的出现次数。遍历字符串中的每个字符,更新其在 map 中的计数。

  1. 计算回文串长度

  • 初始化 sum 为0,用于存储可以构成的最长回文串的长度。

  • 遍历map中的每个字符及其出现次数:

    • 如果出现次数是偶数,则可以完全加入到回文串中,直接加到 sum

    • 如果出现次数是奇数,则将其减一后加入到 sum,并标记存在奇数值的键,以便后续可以在回文串的中心添加一个字符。

  1. 中心字符处理

  • 如果存在奇数值的键,说明可以在回文串的中心添加一个字符,因此在 sum 上加1。

  1. 返回结果

  • 最后返回 sum,即为通过给定字符串构造的最长回文串的长度。

import java.util.HashMap;  
import java.util.Map;  class Solution {  public int longestPalindrome(String s) {  // 检查字符串是否为空  if (s.length() == 0) {  return 0; // 如果字符串为空,直接返回0  }  int sum = 0; // 用于存储可以构成的最长回文串的长度  boolean hasOddValue = false; // 用于跟踪是否存在奇数值的键  Map<Character, Integer> map = new HashMap<>(); // 创建一个HashMap来存储字符及其出现次数  // 遍历字符串中的每个字符  for (char ch : s.toCharArray()) {  // 更新字符的出现次数  map.put(ch, map.getOrDefault(ch, 0) + 1);  }  // 遍历字符计数的映射  for (Map.Entry<Character, Integer> entry : map.entrySet()) {  int value = entry.getValue(); // 获取当前字符的出现次数  if (value % 2 == 0) { // 如果出现次数是偶数  sum += value; // 偶数部分可以完全加入到回文串中  } else { // 如果出现次数是奇数  sum += (value - 1); // 奇数部分减一后加入到回文串中  hasOddValue = true; // 标记存在奇数值的键  }  }  // 如果存在奇数值的键,则可以在回文串的中心添加一个字符  if (hasOddValue) {  sum += 1; // 增加1以考虑中心字符  }  return sum; // 返回计算得到的最长回文串长度  }  // 辅助方法:检查字符串中的所有字符是否相同  private boolean allCharactersSame(String s) {  char firstChar = s.charAt(0); // 获取第一个字符  for (int i = 1; i < s.length(); i++) {  if (s.charAt(i) != firstChar) {  return false; // 如果发现不同的字符,返回false  }  }  return true; // 所有字符相同,返回true  }  
}

第二种思路: 采用官方的贪心思路(不管我暂时还没有从官方的解释中体会到贪心体现在哪里)

解释:那么我们如何通过给定的字符构造一个回文串呢?我们可以将每个字符使用偶数次,使得它们根据回文中心对称。在这之后,如果有剩余的字符,我们可以再取出一个,作为回文中心。

于每个字符 ch,假设它出现了 v 次,我们可以使用该字符 v / 2 * 2 次,在回文串的左侧和右侧分别放置 v / 2 个字符 ch,其中 / 为整数除法。例如若 "a" 出现了 5 次,那么我们可以使用 "a" 的次数为 4,回文串的左右两侧分别放置 2 个 "a"。

如果有任何一个字符 ch 的出现次数 v 为奇数(即 v % 2 == 1),那么可以将这个字符作为回文中心,注意只能最多有一个字符作为回文中心。在代码中,我们用 ans 存储回文串的长度,由于在遍历字符时,ans 每次会增加 v / 2 * 2,因此 ans 一直为偶数。但在发现了第一个出现次数为奇数的字符后,我们将 ans 增加 1,这样 ans 变为奇数,在后面发现其它出现奇数次的字符时,我们就不改变 ans 的值了。

详情见:409. 最长回文串 - 力扣(LeetCode)icon-default.png?t=O83Ahttps://leetcode.cn/problems/longest-palindrome/

  1. 字符计数

    • 使用一个长度为128的数组 count 来统计字符串中每个字符的出现次数。数组的索引对应字符的ASCII值。

    • 遍历字符串 s,对于每个字符 c,增加 count[c] 的值。

  2. 计算回文串长度

    • 初始化 ans 为0,用于存储可以构成的最长回文串的长度。

    • 遍历count数组,对于每个字符的出现次数v:

      • 使用 v / 2 * 2 计算出可以组成的偶数部分,并加到 ans 中。这样可以确保回文串的左右两边是对称的。

      • 如果 v 是奇数,并且当前的 ans 是偶数,说明可以在回文串的中心添加一个字符(即使得回文串的长度增加1),因此将 ans 加1。

  3. 返回结果

    • 最后返回 ans,即为通过给定字符串构造的最长回文串的长度。

class Solution {  public int longestPalindrome(String s) {  // 创建一个长度为128的数组,用于统计字符的出现次数  int[] count = new int[128];  int length = s.length();  // 遍历字符串,统计每个字符的出现次数  for (int i = 0; i < length; ++i) {  char c = s.charAt(i);  count[c]++; // 增加字符c的计数  }  int ans = 0; // 用于存储最长回文串的长度  // 遍历计数数组,计算可以构成的回文串长度  for (int v : count) {  ans += v / 2 * 2; // 将偶数部分直接加到ans中  // 如果当前字符的出现次数为奇数,并且ans是偶数,则可以加1  if (v % 2 == 1 && ans % 2 == 0) {  ans++; // 可以在回文串的中心添加一个字符  }  }  return ans; // 返回计算得到的最长回文串长度  }  
}

455.分发饼干(简单)

题目:假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是满足尽可能多的孩子,并输出这个最大数值。

示例 1:

输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干,3 个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是 1,你只能让胃口值是 1 的孩子满足。
所以你应该输出 1。

示例 2:

输入: g = [1,2], s = [1,2,3]
输出: 2
解释: 
你有两个孩子和三块小饼干,2 个孩子的胃口值分别是 1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出 2。

第一种思路: 首先采用之前刷题的经验,先把这两个数组进行排序,减少工作量。

然后使用双指针的方法遍历两个数组,避免双重循环。

具体而言:

  1. 排序:首先对孩子的胃口数组 g 和饼干的大小数组 s 进行排序。这是为了能够从最小的胃口和最小的饼干开始进行比较,确保尽可能多的孩子能够得到满足。

  2. 双指针法:使用两个指针 childIndexcookieIndex 分别指向孩子和饼干的当前索引。childIndex 用于遍历孩子,cookieIndex 用于遍历饼干。

  3. 满足条件

    • 如果当前饼干可以满足当前孩子的胃口,即 g[childIndex] <= s[cookieIndex],则增加满足的孩子计数 contentChildrenCount,并同时移动到下一个孩子和下一个饼干。

    • 如果当前饼干不能满足当前孩子,则只移动到下一个饼干,继续尝试满足当前孩子。

  4. 结束条件:当遍历完所有孩子或所有饼干时,循环结束,返回满足的孩子数量。

class Solution {  public int findContentChildren(int[] g, int[] s) {  // 对孩子的胃口和饼干的大小进行排序  Arrays.sort(g);  Arrays.sort(s);  int contentChildrenCount = 0; // 记录满足的孩子数量  int childIndex = 0; // 当前孩子的索引  int cookieIndex = 0; // 当前饼干的索引  // 遍历孩子和饼干,直到其中一个数组遍历完  while (childIndex < g.length && cookieIndex < s.length) {  // 如果当前饼干可以满足当前孩子的胃口  if (g[childIndex] <= s[cookieIndex]) {  contentChildrenCount++; // 满足一个孩子  childIndex++; // 移动到下一个孩子  }  // 无论饼干是否满足孩子,都要移动到下一个饼干  cookieIndex++;  }  return contentChildrenCount; // 返回满足的孩子数量  }  
}

后面发现官方的解答和我类似,但是他就是使用双重循环的,想了一下。

贪心算法的贪心在这里面体现在哪?

在这个问题中,贪心算法的贪心策略体现在以下几个方面:

  1. 局部最优选择

    • 每次选择当前最小的饼干来满足当前最小的孩子的胃口。这种选择是基于局部最优的原则,即在每一步中都选择能够立即满足当前孩子的最小饼干。通过这种方式,尽可能多的孩子能够得到满足。

  2. 排序

    • 通过对孩子的胃口和饼干的大小进行排序,确保我们可以从最小的开始进行比较。这种排序使得我们能够有效地找到最小的满足条件的饼干,从而实现贪心选择。

  3. 不回溯

    • 一旦选择了一个饼干来满足一个孩子,就不会回头去尝试用这个饼干去满足其他孩子。每次都向前推进,确保每个孩子都尽可能得到满足,而不去重新考虑之前的选择。

  4. 全局最优解的构建

    • 通过不断地做出局部最优选择(即用当前最小的饼干满足当前最小的孩子),最终构建出全局最优解(即最大数量的孩子得到满足)。这种策略在许多贪心算法中都是常见的。

总结

贪心算法在这个问题中的核心思想是通过局部最优选择(最小饼干满足最小胃口)来达到全局最优解(最大数量的孩子得到满足)。这种方法简单高效,适合解决此类问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/425802.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Understanding the model of openAI 5 (1024 unit LSTM reinforcement learning)

题意&#xff1a;理解 OpenAI 5&#xff08;1024 单元 LSTM 强化学习&#xff09;的模型 问题背景&#xff1a; I recently came across openAI 5. I was curious to see how their model is built and understand it. I read in wikipedia that it "contains a single l…

从0-1 用AI做一个赚钱的小红书账号(不是广告不是广告)

大家好&#xff0c;我是胡广&#xff01;是不是被标题吸引过来的呢&#xff1f;是不是觉得自己天赋异禀&#xff0c;肯定是那万中无一的赚钱天才。哈哈哈&#xff0c;我告诉你&#xff0c;你我皆是牛马&#xff0c;不要老想着突然就成功了&#xff0c;一夜暴富了&#xff0c;瞬…

【SQL】百题计划:SQL对于空值的比较判断。

[SQL]百题计划 方法&#xff1a; 使用 <> (!) 和 IS NULL [Accepted] 想法 有的人也许会非常直观地想到如下解法。 SELECT name FROM customer WHERE referee_Id <> 2;然而&#xff0c;这个查询只会返回一个结果&#xff1a;Zach&#xff0c;尽管事实上有 4 个…

React js Router 路由 2, (把写过的几个 app 组合起来)

完整的项目&#xff0c;我已经上传了&#xff0c;资源链接. 起因&#xff0c; 目的: 每次都是新建一个 react 项目&#xff0c;有点繁琐。 刚刚学了路由&#xff0c;不如写一个 大一点的 app &#xff0c;把前面写过的几个 app, 都包含进去。 这部分感觉就像是&#xff0c; …

linux网络编程——UDP编程

写在前边 本文是B站up主韦东山的4_8-3.UDP编程示例_哔哩哔哩_bilibili视频的笔记&#xff0c;其中有些部分博主也没有理解&#xff0c;希望各位辩证的看。 UDP协议简介 UDP 是一个简单的面向数据报的运输层协议&#xff0c;在网络中用于处理数据包&#xff0c;是一种无连接的…

借助大模型将文档转换为视频

利用传统手段将文档内容转换为视频&#xff0c;比如根据文档内容录制一个视频&#xff0c;不仅需要投入大量的时间和精力&#xff0c;而且往往需要具备专业的视频编辑技能。使用大模型技术可以更加有效且智能化地解决上述问题。本实践方案旨在依托大语言模型&#xff08;Large …

JDBC导图

思维歹徒 一、使用步骤 二、SQL注入 三、数据库查询&#xff08;查询&#xff09; 四、数据库写入&#xff08;增删改&#xff09; 五、Date日期对象处理 六、连接池使用 创建连接是从连接池拿&#xff0c;释放连接是放回连接池 七、事务和批次插入 八、Apache Commons DBUtil…

Village Exteriors Kit 中世纪乡村房屋场景模型

此模块化工具包就是你一直在寻找的适合建造所有中世纪幻想村庄和城市建筑所需要的工具包。 皇家园区 - 村庄外饰套件的模型和纹理插件资源包 酒馆和客栈、魔法商店、市政大厅、公会大厅、布莱克史密斯锻造厂、百货商店、珠宝商店、药店、草药师、银行、铠甲、弗莱切、马厩、桌…

这个时代唯一“不变“的又是{变}

这个时代唯一不变的就是“变”&#xff0c;所以每个人都得有规划意识&#xff0c;首先要对自己的价值有清晰的认知&#xff0c;你核心卖点是什么。第二&#xff0c;你取得的成绩是通过平台成就的还是通过自身努力取得的&#xff0c;很多人在一家平台待久了之后&#xff0c;身上…

2022高教社杯全国大学生数学建模竞赛C题 问题一(1) Python代码

目录 问题 11.1 对这些玻璃文物的表面风化与其玻璃类型、纹饰和颜色的关系进行分析数据探索 -- 单个分类变量的绘图树形图条形图扇形图雷达图 Cramer’s V 相关分析统计检验列联表分析卡方检验Fisher检验 绘图堆积条形图分组条形图 分类模型Logistic回归随机森林 import matplo…

在STM32工程中使用Mavlink与飞控通信

本文讲述如何在STM32工程中使用Mavlink协议与飞控通信&#xff0c;特别适合自制飞控外设模块的项目。 需求来源&#xff1a; 1、增稳云台里的STM32单片机需要通过串口接收飞控传来的云台俯仰、横滚控制指令和相机拍照控制指令&#xff1b; 2、自制的有害气体采集器需要接收飞…

[Python可视化]数据可视化在医疗领域应用:提高诊断准确性和治疗效果

随着医疗数据的增长&#xff0c;如何从庞大的数据集中快速提取出有用的信息&#xff0c;成为了医疗研究和实践中的一大挑战。数据可视化在这一过程中扮演了至关重要的角色&#xff0c;它能够通过图形的方式直观展现复杂的数据关系&#xff0c;从而帮助医生和研究人员做出更好的…

专题四_位运算( >> , << , , | , ^ )_算法详细总结

目录 位运算 常见位运算总结 1.基础位运算 2.给一个数 n ,确定它的二进制表示中的第 x 位是 0 还是 1 3.运算符的优先级 4.将一个数 n 的二进制表示的第 x 位修改成 1 5.将一个数n的二进制表示的第x位修改成0 6.位图的思想 7.提取一个数&#xff08;n&#xff09;二进…

【嘉立创EDA】画PCB板中为什么要两面铺铜为GND,不能一面GND一面VCC吗?

在新手画板子铺铜时&#xff0c;经常会铺一面GND一面VCC。但一般情况下我们不会这样铺铜。下面将详细分析为什么要两面铺铜为GND&#xff0c;而不是一面GND一面VCC的原因&#xff1a; 提高散热能力 金属导热性&#xff1a;金属具有良好的导热性&#xff0c;铺铜可以有效分散PCB…

引用和指针的区别(面试概念性题型)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 概念概述 内存占用&#xff1a; 引用&#xff1a;引用一个变量时&#xff0c;实际上并…

2024 年浙江省网络安全行业网络安全运维工程师项目 职业技能竞赛网络安全运维工程师(决赛样题)

2024年浙江省网络安全行业网络安全运维工程师项目 职业技能竞赛网络安全运维工程师&#xff08;决赛样题&#xff09; 应急响应&#xff1a;1 通过流量分析&#xff0c;找到攻击者的 IP 地址2 找到攻击者下载的恶意文件的 32 位小写 md5 值3 找到攻击者登录后台的 URI4 找到攻击…

攻防世界--->hackme

学习笔记。 下载 查壳。 64ida打开。 进入main&#xff1a; 跟进&#xff1a; 这是密文 咋一看这程序感觉很复杂&#xff0c;很复杂&#xff1a; 脚本&#xff1a; #include <stdio.h> #include <string.h> #include <stdlib.h>int main() {unsigned char …

【数据结构】线段树复杂应用

1.线段树离散化 逆序对 1.1逆序对 题目描述 猫猫 TOM 和小老鼠 JERRY 最近又较量上了&#xff0c;但是毕竟都是成年人&#xff0c;他们已经不喜欢再玩那种你追我赶的游戏&#xff0c;现在他们喜欢玩统计。 最近&#xff0c;TOM 老猫查阅到一个人类称之为“逆序对”的东西&…

小程序开发设计-第一个小程序:创建小程序项目④

上一篇文章导航&#xff1a; 小程序开发设计-第一个小程序&#xff1a;安装开发者工具③-CSDN博客https://blog.csdn.net/qq_60872637/article/details/142219152?spm1001.2014.3001.5501 须知&#xff1a;注&#xff1a;不同版本选项有所不同&#xff0c;并无大碍。 一、创…

5G Multicast/Broadcast Services(MBS) (二) Multicast

这篇是Multicast handling的overview,正文开始。 值得注意的是,对于5MBS multicast,UE只有处于RRC connected和Inactive时,网络侧才可以通过MRB将MBS multicast数据传输到 UE;处于Idle态只能进行MBS broadcast过程。 对于multicast涉及的RNTI有G-RNTI,G-CS-RNTI以及在RRC …