文章目录
- [HJ30 字符串合并处理](#HJ30 字符串合并处理)
HJ30 字符串合并处理
题目描述
对于给定的由大小写字母和数字构成的字符串 s 和 t,记下标从 1 开始。按以下两个阶段进行处理:
【合并阶段】
- 第一步,将 s 和 t 合并,形成一个新字符串 u。
- 第二步,将 u 中奇数位字符按 Ascii 码从小到大('A'<'B'<⋯<'Z'<'a'<⋯<'z')进行排序,随后将偶数位字符也按 Ascii 码从小到大进行排序,得到 u'。
【调整阶段】
随后,从左到右遍历 u' 中的每一个字符 u'i:
- 第一步,若 u'i 不是合法十六进制字符(即不为0-9、a-f、A-F),则保留原字符,直接追加到结果中;否则,将其转换为十进制数。
- 第二步,将该十进制数转换为四位二进制数(高位不足补 0,例如 (5)10 = (0101)2);
- 第三步,将该二进制数翻转(反过来书写);
- 第四步,将该二进制数转换为大写的十六进制数,追加到结果中。
最终输出上述拼接而成的字符串。
输入描述
在一行上输入两个长度 1<=length(s),length(t)<=100,由大小写字母和数字构成的字符串 s 和 t,代表待处理的字符串。
输出描述
输出处理后的最终字符串。
示例1
输入:dec fab
输出:5D37BF
说明: 在这个样例中,全过程描述如下:
【合并阶段】
-
第一步合并得到 u="decfab";
-
第二步排序得到 u'="abcedf"。
【调整阶段】
-
对于第一个字符 (a)16,其十进制数为 (10)10,二进制数为 (1010)2,翻转后得到 (0101)2;再转换回十六进制数为 (5)16;
-
对于第二个字符 (b)16,其十进制数为 (11)10,二进制数为 (1011)2,翻转后得到 (1101)2;再转换回十六进制数为 (D)16;
-
对于第三个字符 ©16,其十进制数为 (12)10,二进制数为 (1100)2,翻转后得到 (0011)2;再转换回十六进制数为 (3)16;
-
对于第四个字符 (d)16,其十进制数为 (13)10,二进制数为 (1101)2,翻转后得到 (1011)2;再转换回十六进制数为 (B)16;
-
对于第五个字符 (e)16,其十进制数为 (14)10,二进制数为 (1110)2,翻转后得到 (0111)2;再转换回十六进制数为 (7)16;
-
对于第六个字符 (f)16,其十进制数为 (15)10,二进制数为 (1111)2,翻转后得到 (1111)2;再转换回十六进制数为 (F)16;
-
最终输出拼接而成的字符串。
示例2
输入:abV CDw
输出:B3VD5w
说明:在这个样例中,全过程描述如下:
【合并阶段】
-
第一步合并得到 u="abVCDw";
-
第二步排序得到 u'="DCVbaw"。
【调整阶段】
-
对于第一个字符 (D)16,其十进制数为 (13)10,二进制数为 (1101)2,翻转后得到 (1011)2;再转换回十六进制数为 (B)16;
-
对于第二个字符 ©16,其十进制数为 (12)10,二进制数为 (1100)2,翻转后得到 (0011)2;再转换回十六进制数为 (3)16;
-
对于第三个字符 (V)16,跳过该字符;
-
对于第四个字符 (b)16,其十进制数为 (11)10,二进制数为 (1011)2,翻转后得到 (1101)2;再转换回十六进制数为 (D)16;
-
对于第五个字符 (a)16,其十进制数为 (10)10,二进制数为 (1010)2,翻转后得到 (0101)2;再转换回十六进制数为 (5)16;
-
对于第六个字符 (w)16,跳过该字符;
示例3
输入:123 15
输出:88C4A
说明:在这个样例中,全过程描述如下:
【合并阶段】
-
第一步合并得到 u="12315";
-
第二步排序得到 u'="11325"。
【调整阶段】
-
对于第一个字符 (1)16,其十进制数为 (1)10,二进制数为 (0001)2,翻转后得到 (1000)2;再转换回十六进制数为 (8)16;
-
对于第二个字符 (1)16,其十进制数为 (1)10,二进制数为 (0001)2,翻转后得到 (1000)2;再转换回十六进制数为 (8)16;
-
对于第三个字符 (3)16,其十进制数为 (3)10,二进制数为 (0011)2,翻转后得到 (1100)2;再转换回十六进制数为 ©16;
-
对于第四个字符 (2)16,其十进制数为 (2)10,二进制数为 (0010)2,翻转后得到 (0100)2;再转换回十六进制数为 (4)16;
-
对于第五个字符 (5)16,其十进制数为 (5)10,二进制数为 (0101)2,翻转后得到 (1010)2;再转换回十六进制数为 (A)16;
解题思路
算法分析
这道题的核心是字符串处理 和进制转换。主要涉及:
- 字符串合并:简单拼接两个字符串
- 奇偶位分离排序:按位置分离字符并分别排序
- 十六进制字符识别:判断字符是否为0-9、a-f、A-F
- 进制转换:十六进制→十进制→二进制→翻转→十六进制
算法流程图
否 是 是 否 输入字符串s和t 合并: u = s + t 分离奇偶位字符 奇数位排序 偶数位排序 重新组合: u' 遍历u'中每个字符 是否为十六进制字符? 直接添加到结果 转换为十进制 转换为4位二进制 翻转二进制 转换为大写十六进制 添加到结果 还有字符? 输出最终结果
合并阶段详解
字符串s 合并u = s + t 字符串t 按位置分离 奇数位: 1,3,5,... 偶数位: 2,4,6,... ASCII排序 ASCII排序 重新组合u'
调整阶段详解
进制转换过程
十六进制a 十进制10 二进制1010 翻转0101 十进制5 十六进制5
代码实现思路
-
合并阶段:
- 字符串拼接:
u = s + t
- 奇偶位分离:按下标(i+1)%2判断
- ASCII排序:使用
sort.Slice()
- 重新组合:奇数位在前,偶数位在后
- 字符串拼接:
-
调整阶段:
- 十六进制判断:范围检查0-9、a-f、A-F
- 进制转换:使用标准库函数
- 二进制翻转:字符串反转算法
- 结果拼接:使用
strings.Builder
时间复杂度分析
- 时间复杂度:O(n log n),主要是排序操作
- 空间复杂度:O(n),用于存储分离的字符和结果
关键优化点
- 字符分离优化:一次遍历分离奇偶位
- 排序优化:使用Go标准库的高效排序
- 字符串构建优化 :使用
strings.Builder
避免频繁内存分配 - 进制转换优化:使用标准库函数和格式化
边界情况处理
- 空字符串:合并后为空或单个字符
- 全十六进制字符:所有字符都需要转换
- 无十六进制字符:所有字符都保持原样
- 单字符字符串:只有奇数位或偶数位
算法特点
- 多阶段处理:合并阶段和调整阶段分离
- 复杂转换:涉及多种进制转换
- 字符分类:需要识别十六进制字符
- 位置相关:奇偶位分别处理
实现细节
奇偶位判断 i+1%2 == 1为奇数位 十六进制判断 0-9, a-f, A-F 二进制翻转 字符串首尾交换 大写转换 strings.ToUpper
这个问题的关键在于正确理解题目的两个阶段 和准确实现进制转换过程,特别是二进制翻转和十六进制字符的识别处理。
完整题解代码
go
package main
import (
"fmt"
"sort"
"strconv"
"strings"
)
func main() {
var s, t string
fmt.Scan(&s, &t)
result := processString(s, t)
fmt.Println(result)
}
func processString(s, t string) string {
// 合并阶段
u := s + t
// 分离奇偶位字符(按1开始的下标)
var oddChars, evenChars []rune
for i, char := range u {
if (i+1)%2 == 1 { // 奇数位(下标从1开始)
oddChars = append(oddChars, char)
} else { // 偶数位
evenChars = append(evenChars, char)
}
}
// 按ASCII码排序
sort.Slice(oddChars, func(i, j int) bool {
return oddChars[i] < oddChars[j]
})
sort.Slice(evenChars, func(i, j int) bool {
return evenChars[i] < evenChars[j]
})
// 重新组合:按奇偶位交替排列
var uPrime strings.Builder
maxLen := len(oddChars)
if len(evenChars) > maxLen {
maxLen = len(evenChars)
}
for i := 0; i < maxLen; i++ {
if i < len(oddChars) {
uPrime.WriteRune(oddChars[i])
}
if i < len(evenChars) {
uPrime.WriteRune(evenChars[i])
}
}
// 调整阶段
var result strings.Builder
for _, char := range uPrime.String() {
if isHexChar(char) {
// 转换为十进制
decValue := hexToDecimal(char)
// 转换为4位二进制
binary := fmt.Sprintf("%04b", decValue)
// 翻转二进制
reversed := reverseString(binary)
// 转换回十六进制并转为大写
reversedDec, _ := strconv.ParseInt(reversed, 2, 64)
hexResult := strings.ToUpper(fmt.Sprintf("%X", reversedDec))
result.WriteString(hexResult)
} else {
// 非十六进制字符直接添加
result.WriteRune(char)
}
}
return result.String()
}
func isHexChar(char rune) bool {
return (char >= '0' && char <= '9') ||
(char >= 'a' && char <= 'f') ||
(char >= 'A' && char <= 'F')
}
func hexToDecimal(char rune) int {
if char >= '0' && char <= '9' {
return int(char - '0')
}
if char >= 'a' && char <= 'f' {
return int(char - 'a' + 10)
}
if char >= 'A' && char <= 'F' {
return int(char - 'A' + 10)
}
return 0
}
func reverseString(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}