华为OD机试真题 新系统 2026-04-29 Java&Go&C语言 实现【获取大写字母瓷砖拼出独特图案数量】
目录
题目
在一个创意设计工坊中,设计师 希望用不同的大写字母瓷砖拼出独特图案,给定一个只包含大写英文字母的图案字符串 L,要求你给出对 L重新排列的所有不相同的图案,但是有以下约束条件:
相同的字母不能相邻
输入描述
输入一个长度不超过 12 的字符串 L,确保都是大写的输出描述
输出满足约束条件的L重新排列的所有不相同的排列数用例1
输入
"AAB"
输出
1
说明
只有ABA满足条件用例2
输入
""
输出
1
说明
空字符串也是符合没有相邻的要求
思路
长度上限只有 12, 无所谓速度快慢了,“字符计数 + 回溯”。
核心想法:
- 先统计每个字母还剩多少个可用
- 每次递归放下一个字符时:
- 只能放“剩余数量大于 0”的字符
- 不能和上一个放入的字符相同
- 当已经放满 n 个字符时,说明找到一种合法排列,答案加一
Code
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.TreeMap;
public class Main {
static Map<Character, Integer> counter = new TreeMap<>();
static char[] letters;
static int totalLen;
static long answer = 0;
static void dfs(char lastChar, int usedLen) {
// 已经放满全部字符,说明找到一种合法排列。
if (usedLen == totalLen) {
answer++;
return;
}
// 枚举每一种还剩余的字符。
for (char ch : letters) {
int remain = counter.get(ch);
// 当前字符已经用完,跳过。
if (remain == 0) {
continue;
}
// 不能与上一个放入的字符相同。
if (ch == lastChar) {
continue;
}
// 选择当前字符,递归处理下一位。
counter.put(ch, remain - 1);
dfs(ch, usedLen + 1);
// 回溯,恢复现场。
counter.put(ch, remain);
}
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
String line;
// 读取全部输入,兼容末尾换行。
while ((line = br.readLine()) != null) {
sb.append(line);
}
String s = sb.toString().trim();
// 输入固定为带双引号的字符串,这里取出双引号内部内容。
// 例如 "AAB" -> AAB,"" -> 空字符串。
if (s.length() >= 2 && s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"') {
s = s.substring(1, s.length() - 1);
}
// 空字符串只有一种合法排列。
if (s.isEmpty()) {
System.out.print(1);
return;
}
totalLen = s.length();
// 统计每个字符的剩余数量。
for (char ch : s.toCharArray()) {
counter.put(ch, counter.getOrDefault(ch, 0) + 1);
}
// TreeMap 天然有序,这里取出有序字符集合。
letters = new char[counter.size()];
int idx = 0;
for (char ch : counter.keySet()) {
letters[idx++] = ch;
}
dfs('\0', 0);
System.out.print(answer);
}
}
Go
package main
import (
"fmt"
"io"
"os"
"sort"
"strings"
)
var (
counter map[byte]int
letters []byte
totalLen int
answer int
)
func dfs(lastChar byte, usedLen int) {
// 已经放满全部字符,说明找到一种合法排列。
if usedLen == totalLen {
answer++
return
}
// 枚举还剩余的字符。
for _, ch := range letters {
if counter[ch] == 0 {
continue
}
// 相同字符不能相邻。
if ch == lastChar {
continue
}
// 选择当前字符。
counter[ch]--
dfs(ch, usedLen+1)
// 回溯恢复。
counter[ch]++
}
}
func main() {
data, _ := io.ReadAll(os.Stdin)
s := strings.TrimSpace(string(data))
// 输入固定为带双引号的字符串,这里取出双引号内部内容。
if len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' {
s = s[1 : len(s)-1]
}
// 空字符串只有一种排列。
if s == "" {
fmt.Print(1)
return
}
counter = make(map[byte]int)
for i := 0; i < len(s); i++ {
counter[s[i]]++
}
// 保存所有不同字符,并排序保证遍历稳定。
letters = make([]byte, 0, len(counter))
for ch := range counter {
letters = append(letters, ch)
}
sort.Slice(letters, func(i, j int) bool {
return letters[i] < letters[j]
})
totalLen = len(s)
dfs(0, 0)
fmt.Print(answer)
}
C
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char letters[26];
int counts[26];
int letterCount = 0;
int totalLen = 0;
long long answer = 0;
void dfs(char lastChar, int usedLen) {
// 已经放满全部字符,说明得到一种合法排列。
if (usedLen == totalLen) {
answer++;
return;
}
// 枚举所有仍可使用的字符。
for (int i = 0; i < letterCount; i++) {
char ch = letters[i];
int idx = ch - 'A';
// 当前字符没有剩余了,跳过。
if (counts[idx] == 0) {
continue;
}
// 相同字母不能相邻。
if (ch == lastChar) {
continue;
}
// 选择当前字符。
counts[idx]--;
dfs(ch, usedLen + 1);
// 回溯,恢复剩余数量。
counts[idx]++;
}
}
int main() {
char raw[1000];
int len = 0;
int ch;
// 读取全部输入。
while ((ch = getchar()) != EOF) {
raw[len++] = (char)ch;
}
raw[len] = '\0';
// 去掉首尾空白字符。
int left = 0, right = len - 1;
while (left <= right && isspace((unsigned char)raw[left])) left++;
while (right >= left && isspace((unsigned char)raw[right])) right--;
char s[1000];
int p = 0;
for (int i = left; i <= right; i++) {
s[p++] = raw[i];
}
s[p] = '\0';
// 输入固定为带双引号的字符串,这里取出双引号内部内容。
if ((int)strlen(s) >= 2 && s[0] == '"' && s[strlen(s) - 1] == '"') {
int n = (int)strlen(s);
memmove(s, s + 1, n - 2);
s[n - 2] = '\0';
}
// 空字符串只有一种合法排列。
if (strlen(s) == 0) {
printf("1");
return 0;
}
totalLen = (int)strlen(s);
// 统计每个字符出现次数。
for (int i = 0; s[i] != '\0'; i++) {
counts[s[i] - 'A']++;
}
// 提取所有出现过的不同字符。
for (int i = 0; i < 26; i++) {
if (counts[i] > 0) {
letters[letterCount++] = (char)('A' + i);
}
}
dfs('\0', 0);
printf("%lld", answer);
return 0;
}
【华为od机试真题Python+JS+Java+Go合集】【超值优惠】:Py/JS/Java/Go合集
【华为od机试真题Python】:Python真题题库
【华为od机试真题JavaScript】:JavaScript真题题库
【华为od机试真题Java&Go】:Java&Go真题题库
【华为od机试真题C++】:C++真题题库
【华为od机试真题C语言】:C语言真题题库
【华为od面试手撕代码题库】:面试手撕代码题库
【华为od机试面试交流群】【文章底部有二维码链接,可扫码加交流群】
华为OD机试:二本院校有机会吗?
有机会,但不大,大神除外!机考分数越高越好,所以需要提前刷题。机考通过后,如果没有收到面试邀请,也不要着急,非目标院校面试邀请发的时间比较晚。非目标院校今年有点难,机试至少要考到350分,所以需要疯狂刷题,华为OD机考是有题库的,最好在考前完所有题库题目。华为OD机试:跨专业可以参加华为OD可以,但是如果你的本科院校比较差,上岸概率不大。华为OD机试:华为OD简历被锁定机试通过,性格测试也通过,但是没人联系面试,发现简历被锁定。此时需要主动去联系HR。让他帮助你查询原因。
更多推荐





所有评论(0)