3035. 回文字符串的最大数量

简介: 3035. 回文字符串的最大数量

说在前面

🎈不知道大家对于算法的学习是一个怎样的心态呢?为了面试还是因为兴趣?不管是出于什么原因,算法学习需要持续保持。

题目描述

给你一个下标从 0 开始的字符串数组 words ,数组的长度为 n ,且包含下标从 0 开始的若干字符串。

你可以执行以下操作 任意 次数(包括零次):

  • 选择整数ijxy,满足0 <= i, j < n0 <= x < words[i].length0 <= y < words[j].length交换 字符 words[i][x]words[j][y]

返回一个整数,表示在执行一些操作后,words 中可以包含的回文字符串的 最大 数量。

注意: 在操作过程中,ij 可以相等。

示例 1:

输入: words = ["abbb","ba","aa"]
输出: 3
解释: 在这个例子中,获得最多回文字符串的一种方式是:
选择 i = 0, j = 1, x = 0, y = 0,交换 words[0][0] 和 words[1][0] 。words 变成了 ["bbbb","aa","aa"] 。
words 中的所有字符串都是回文。
因此,可实现的回文字符串的最大数量是 3 。

示例 2:

输入: words = ["abc","ab"]
输出: 2
解释: 在这个例子中,获得最多回文字符串的一种方式是: 
选择 i = 0, j = 1, x = 1, y = 0,交换 words[0][1] 和 words[1][0] 。words 变成了 ["aac","bb"] 。
选择 i = 0, j = 0, x = 1, y = 2,交换 words[0][1] 和 words[0][2] 。words 变成了 ["aca","bb"] 。
两个字符串都是回文 。
因此,可实现的回文字符串的最大数量是 2。

示例 3:

输入: words = ["cd","ef","a"]
输出: 1
解释: 在这个例子中,没有必要执行任何操作。
words 中有一个回文 "a" 。
可以证明,在执行任何次数操作后,无法得到更多回文。
因此,答案是 1 。

提示:

  • 1 <= words.length <= 1000
  • 1 <= words[i].length <= 100
  • words[i] 仅由小写英文字母组成。

解题思路

这道题目主要考察的是贪心策略,我们要思考怎么操作才能得到最多的回文字符串,首先我们需要先明确一下回文字符串的定义:

回文字符串是指正读和反读都相同的字符串。换句话说,它从左到右读和从右到左读是一样的。例如,“level”、"radar"和"madam"都是回文字符串。回文字符串可以包含字母、数字或其他字符。

我们可以根据其长度将回文字符串分为两类:

  • 1、长度为奇数

则其会有(length - 1) / 2 对相同字符,及一个单独的字符,当然,多对字符串之间可以是相同的,成对字符串和单独的那个字符串也可以是相同的。

  • 2、长度为偶数

其会有 length / 2 对相同字符,多对字符串之间同样可以是相同的。

题目说的是我们可以交易任意两个位置的字符串的任意两个下标之间的字符,这里的两个位置可以是相同的,也就是说我们可以交换同一个字符串里不同下标的字符,换句话说,我们可以使用原有字符串的所有字符进行重组,只需要保证重组的每个字符串长度和原来的字符串长度一致就行。

知道这个之后我们便可以开始编写代码了:

1、统计各个字母出现

const cnt = new Array(26).fill(0);
for (const word of words) {
  for (let i = 0; i < word.length; i++) {
    const ind = word[i].charCodeAt() - 97;
    cnt[ind]++;
  }
}

2、统计成对及落单字母的数量

let d = 0,
  s = 0;
for (let i = 0; i < cnt.length; i++) {
  if (cnt[i] % 2 === 0) d += cnt[i];
  else {
    s += 1;
    d += cnt[i] - 1;
  }
}

3、将原有字符串数组按字符串长度从小到大排序

为了得到更多的回文字符串,我们应该优先重组长度更小的字符串,这样的到的字符串数量也就越多。

words.sort((a, b) => a.length - b.length);

4、重组回文字符串

  • 1、需要重组的回文字符串长度为偶数

我们需要使用 length 个成对字符来重组。

  • 2、需要重组的回文字符串长度为奇数

我们需要使用 length - 1 个成对字符和一个单独字符来重组。单独字符用完的时候我们可以将一对成对字符当成两个单独字符来使用。

如果成对字符不够用的话则说明当前字符串及往后的所有字符串都无法重组为回文字符串,我们直接返回当前已经得到的回文字符串数量即可。

for (const word of words) {
  if (word.length % 2 === 0) {
    d -= word.length;
  } else {
    if (s <= 0) {
      d -= 2;
      s += 2;
    }
    d -= word.length - 1;
    s -= 1;
  }
  if (d < 0) return ind;
  ind++;
}

AC代码

/**
 * @param {string[]} words
 * @return {number}
 */
var maxPalindromesAfterOperations = function (words) {
  const cnt = new Array(26).fill(0);
  for (const word of words) {
    for (let i = 0; i < word.length; i++) {
      const ind = word[i].charCodeAt() - 97;
      cnt[ind]++;
    }
  }
  let d = 0,
    s = 0;
  for (let i = 0; i < cnt.length; i++) {
    if (cnt[i] % 2 === 0) d += cnt[i];
    else {
      s += 1;
      d += cnt[i] - 1;
    }
  }
  words.sort((a, b) => a.length - b.length);
  let ind = 0;
  for (const word of words) {
    if (word.length % 2 === 0) {
      d -= word.length;
    } else {
      if (s <= 0) {
        d -= 2;
        s += 2;
      }
      d -= word.length - 1;
      s -= 1;
    }
    if (d < 0) return ind;
    ind++;
  }
  return words.length;
};

公众号

关注公众号『前端也能这么有趣』,获取更多有趣内容。

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

目录
相关文章
|
机器学习/深度学习 编解码 API
深度学习+不良身体姿势检测+警报系统+代码+部署(姿态识别矫正系统)
深度学习+不良身体姿势检测+警报系统+代码+部署(姿态识别矫正系统)
|
资源调度 监控 物联网
《深入探秘:分布式软总线自发现、自组网技术原理》
分布式软总线是实现设备高效互联的关键技术,其自发现与自组网功能为多设备协同奠定了基础。通过融合Wi-Fi、蓝牙、NFC等通信技术,设计针对性发现协议,并采用统一接口封装,简化开发复杂度。自组网技术解决异构网络互联互通问题,支持混合拓扑结构,优化通信资源调度,引入软时钟确保时间同步。这些特性使分布式软总线成为构建万物互联智能时代的核心支撑,推动智能家居、智能办公等领域创新发展,提升生活与工作效率。
676 8
|
7月前
|
弹性计算 负载均衡 定位技术
阿里云服务器ECS【地域】如何选择?不同地域区别及优缺点对比
阿里云服务器地域选择需综合考虑用户地理位置、网络延迟、备案要求、内网互通、价格差异及产品功能等因素。建议根据用户所在地区就近选择地域,以降低延迟、提升访问速度。同时注意地域一旦选定不可更改,需谨慎选择。
1805 155
|
存储 缓存 监控
分布式架构知识体系
本文力求从分布式基础理论,架构设计模式,工程应用,部署运维,业界方案这几大方面,介绍基于MSA(微服务架构)的分布式的知识体系大纲。
1059 13
|
JSON 安全 API
Python调用API接口的方法
Python调用API接口的方法
2111 5
|
Android开发 计算机视觉 C++
FFmpeg开发笔记(五十一)适合学习研究的几个音视频开源框架
音视频编程对许多程序员来说是一片充满挑战的领域,但借助如OpenCV、LearnOpenGL、FFmpeg、OBS Studio及VLC media player等强大的开源工具,可以降低入门门槛。这些框架不仅覆盖了计算机视觉、图形渲染,还包括多媒体处理与直播技术,通过多种编程语言如Python、C++的应用,使得音视频开发更为便捷。例如,OpenCV支持跨平台的视觉应用开发,FFmpeg则擅长多媒体文件的处理与转换,而VLC media player则是验证音视频文件质量的有效工具。
735 0
FFmpeg开发笔记(五十一)适合学习研究的几个音视频开源框架
|
前端开发 程序员 项目管理
Nuxt3 实战 (二):配置 Eslint、Prettierrc、Husky等项目提交规范
这篇文章介绍了项目规范的重要性和如何配置一些工具来提高代码质量、团队协作、降低维护成本、提升软件可靠性和促进项目管理。工具介绍了Eslint和Prettier,并且提供了安装和配置的步骤。文章还提到了如何配置Husky和Commitlint来检查提交风格的规范性,并最后提到了需要使用 release-it 自动管理版本号和生成 CHANGELOG 的任务。
521 0
Nuxt3 实战 (二):配置 Eslint、Prettierrc、Husky等项目提交规范
ARM64技术 —— 系统调用指令SVC、HVC和SMC的使用规则
ARM64技术 —— 系统调用指令SVC、HVC和SMC的使用规则
|
Ubuntu Linux 程序员
交叉编译valgrind在嵌入式设备上调试程序
交叉编译valgrind在嵌入式设备上调试程序
|
存储 安全 Java
Java面试题:在JVM中,堆和栈有什么区别?请详细解释说明,要深入到底层知识
Java面试题:在JVM中,堆和栈有什么区别?请详细解释说明,要深入到底层知识
588 3

热门文章

最新文章

下一篇
开通oss服务