Leetcode之482.密钥格式化
Posted 二木成林
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode之482.密钥格式化相关的知识,希望对你有一定的参考价值。
题目
题目描述
有一个密钥字符串 S ,只包含字母,数字以及 ‘-’(破折号)。其中, N 个 ‘-’ 将字符串分成了 N+1 组。
给你一个数字 K,请你重新格式化字符串,使每个分组恰好包含 K 个字符。特别地,第一个分组包含的字符个数必须小于等于 K,但至少要包含 1 个字符。两个分组之间需要用 ‘-’(破折号)隔开,并且将所有的小写字母转换为大写字母。
给定非空字符串 S 和数字 K,按照上面描述的规则进行格式化。
示例 1:
输入:S = “5F3Z-2e-9-w”, K = 4
输出:“5F3Z-2E9W”
解释:字符串 S 被分成了两个部分,每部分 4 个字符;
注意,两个额外的破折号需要删掉。
示例 2:
输入:S = “2-5g-3-J”, K = 2
输出:“2-5G-3J”
解释:字符串 S 被分成了 3 个部分,按照前面的规则描述,第一部分的字符可以少于给定的数量,其余部分皆为 2 个字符。
提示:
- S 的长度可能很长,请按需分配大小。K 为正整数。
- S 只包含字母数字(a-z,A-Z,0-9)以及破折号’-’
- S 非空
来源
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/license-key-formatting
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
解法1
class Solution {
/**
* <p>思路:Java的API</p>
* <p>步骤:</p>
* <ul>
* <li>第一步,利用Java的API删除掉原字符串中的所有破折号,并且将其全部转换成大写字母</li>
* <li>第二步,倒序循环遍历字符串,每隔K个字符则添加一个破折号</li>
* </ul>
* <p>结果:成功</p>
* <ul>
* <li>执行用时:103 ms, 在所有 Java 提交中击败了8.97% 的用户</li>
* <li>内存消耗:39.1 MB, 在所有 Java 提交中击败了19.39% 的用户</li>
* <li>通过测试用例:38 / 38</li>
* </ul>
*
* @param S 密钥字符串
* @param K 数字K,使得每个分组恰好包含K个字符
* @return 返回格式化后的密钥字符串
*/
public String licenseKeyFormatting(String S, int K) {
// 第一步,利用Java的API删除掉原字符串中的所有破折号,并且将其全部转换成大写字母
S = S.replaceAll("-", "").toUpperCase();
// 第二步,倒序循环遍历字符串,每隔K个字符则添加一个破折号
StringBuilder result = new StringBuilder();// 保存结果的字符串
char[] chars = S.toCharArray();// 将输入字符串S转换成字符数组
int count = 0;// 计数器,记录已经遍历过的字符个数,此时字符串中已经不存在破折号字符了
for (int i = chars.length - 1; i >= 0; i--) {
// 记录字符个数
count++;
// 向StringBuilder中插入一个字符,注意使用头插法(即每个新字符插入到原字符串的头部)插入字符
result.insert(0, chars[i]);
// 当已经遍历K个字符后插入破折号字符,但需要注意当字符数刚好是K的整数倍,则不需要插入分隔字符符号,所以需要添加i!=0的判断
if (count % K == 0 && i != 0) {
result.insert(0, '-');
// 同时将count置为0,开始下一次的记录
count = 0;
}
}
return result.toString();
}
}
解法2
class Solution {
/**
* <p>思路:单指针倒序遍历</p>
* <p>步骤:</p>
* <ul>
* <li>第一步,单指针,倒序遍历字符串,遇到破折号则跳过,同时将当前字符转换为大写字母插入到结果字符串中,当遍历K个字符后(不包括破折号),则插入一个破折号字符</li>
* </ul>
* <p>结果:成功</p>
* <ul>
* <li>执行用时:91 ms, 在所有 Java 提交中击败了12.40% 的用户</li>
* <li>内存消耗:38.4 MB, 在所有 Java 提交中击败了79.16% 的用户</li>
* <li>通过测试用例:38 / 38</li>
* </ul>
*
* @param S 密钥字符串
* @param K 数字K,使得每个分组恰好包含K个字符
* @return 返回格式化后的密钥字符串
*/
public String licenseKeyFormatting(String S, int K) {
// 指针,指向字符串S中的下标,从字符串中的最后一个字符开始
int i = S.length() - 1;
// 计数器,记录字符串S中非破折号字符的个数
int count = 0;
// 保存格式化后的密钥字符串的结果
StringBuilder result = new StringBuilder();
// 倒序遍历字符串
while (i >= 0) {
// 获取当前正在遍历的字符
char c = S.charAt(i);
// 判断如果不是破折号字符则添加到result中
if (c != '-') {
// 非破折号字符个数加一
count++;
// 插入到result中,同时注意将小写字母字符转换成大写字母字符
result.insert(0, c >= 'a' ? (char) (c - 32) : c);
// 当插入K个非破折号字符后,向result中插入破折号字符"-"
if (count == K && i != 0) {
result.insert(0, '-');
count = 0;
}
}
// 继续遍历下一个字符
i--;
}
// 处理s是"--a-a-a-a--"或"---"的特殊情况
return (result.length() > 0 && result.charAt(0) == '-') ? result.substring(1) : result.toString();
}
}
解法3
class Solution {
/**
* <p>思路:栈的先进后出特性。因为要倒序遍历字符串,所以符合先进后出的特性,可以采用栈来实现。</p>
* <p>步骤:</p>
* <ul>
* <li>第一步,将所有非破折号字符并且转换成大写字母字符入栈</li>
* <li>第二步,将栈顶字符出栈,并且每K个字符用破折号字符进行分隔插入到result</li>
* </ul>
* <p>结果:成功</p>
* <ul>
* <li>执行用时:100 ms, 在所有 Java 提交中击败了9.10% 的用户</li>
* <li>内存消耗:39 MB, 在所有 Java 提交中击败了28.36% 的用户</li>
* <li>通过测试用例:38 / 38</li>
* </ul>
*
* @param S 密钥字符串
* @param K 数字K,使得每个分组恰好包含K个字符
* @return 返回格式化后的密钥字符串
*/
public String licenseKeyFormatting(String S, int K) {
// 第一步,将所有非破折号字符并且转换成大写字母字符入栈
int i = 0;
Stack stack = new Stack();
while (i < S.length()) {
char c = S.charAt(i);
if (c != '-') {
// 将非破折号字符,并且将小写字母转换成大写字母填入栈中
stack.push(c >= 'a' ? (char) (c - 32) : c);
}
i++;
}
// 第二步,将栈顶字符出栈,并且每K个字符用破折号字符进行分隔插入到result
StringBuilder result = new StringBuilder();
int count = 0;// 已经插入到result字符串中字符的个数
int len = stack.size();// 非破折号字符的个数
// 循环遍历栈
while (!stack.isEmpty()) {
// 插入到result中的字符加1
count++;
// 将栈顶元素插入到result中,并且将栈顶元素出栈
result.insert(0, stack.pop());
// 每K个字符插入一个破折号字符
if (count % K == 0 && count != len) {
result.insert(0, '-');
}
}
return result.toString();
}
}
解法4
public class Solution {
/**
* <p>思路:数组,将字符存放到数组中,效率更高。</p>
* <p>步骤:</p>
* <ul>
* <li>第一步,统计字符串中非破折号字符的个数,并且将小写字母字符转换成大写字母字符存入原数组</li>
* <li>第二步,倒序将chars数组中的非破折号字符向结果数组result赋值,并且每K个元素插入一个破折号字符</li>
* </ul>
* <p>结果:成功</p>
* <ul>
* <li>执行用时:3 ms, 在所有 Java 提交中击败了100.00% 的用户</li>
* <li>内存消耗:38.6 MB, 在所有 Java 提交中击败了50.13% 的用户</li>
* <li>通过测试用例:38 / 38</li>
* </ul>
*
* @param S 密钥字符串
* @param K 数字K,使得每个分组恰好包含K个字符
* @return 返回格式化后的密钥字符串
*/
public String licenseKeyFormatting(String S, int K) {
// 第一步,统计字符串中非破折号字符的个数,并且将小写字母字符转换成大写字母字符存入原数组
int count = 0;// 字符串中非破折号字符的个数
char[] chars = S.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (chars[i] != '-') {
// 统计非破折号字符的个数
count++;
// 将小写字母字符转换成大写字母字符存入原数组
chars[i] = chars[i] >= 'a' ? (char) (chars[i] - 32) : chars[i];
}
}
// 如果没有字符则返回空字符串
if (count == 0) {
return "";
}
// 计算分隔符的个数
int separator = count / K;
// 如果正好整除,分隔符个数 - 1
separator = count % K == 0 ? separator - 1 : separator;
// 第二步,倒序将chars数组中的非破折号字符向结果数组result赋值,并且每K个元素插入一个破折号字符
char[] result = new char[count + separator];
int index = result.length - 1;// 指向result数组的下标
int letter = 0;// 统计已赋值的字符个数
for (int i = chars.length - 1; i >= 0; i--) {
// 处理非破折号字符
if (chars[i] != '-') {
// 将非破折号字符放入到result数组中
result[index] = chars[i];
index--;
letter++;
// 每K个元素插入一个破折号字符
if (letter % K == 0 && index != -1) {
result[index] = '-';
index--;
}
}
}
return new String(result);
}
}
以上是关于Leetcode之482.密钥格式化的主要内容,如果未能解决你的问题,请参考以下文章
Leetcode刷题100天—482. 密钥格式化(字符)—day57
Leetcode刷题100天—482. 密钥格式化(字符)—day57
LeetCode 405. 数字转换为十六进制数(补码的问题) / 166. 分数到小数(模拟长除法) / 482. 密钥格式化