蓝桥杯java算法例题
一、经典数学问题
1. 约瑟夫问题
问题描述:N 个人围成一圈,从第一个人开始报数,报数到 M 的人出圈,剩下的人继续从 1 开始报数,直到所有人出圈,输出出圈顺序。
核心思路:用队列模拟环形结构,依次弹出元素并计数,计数到 M 时输出该元素,否则重新入队。
package test; import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner; public class Main { public static void main(String[] args) { Queue<Integer> queue = new LinkedList<>(); Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); // 总人数 int m = scanner.nextInt(); // 报数阈值 for (int i = 0; i < n; i++) { queue.add(i); // 初始化队列(0~n-1编号) } int res = 0; while (!queue.isEmpty()) { int x = queue.poll(); res++; if (res == m) { // 达到阈值,输出并重置计数 System.out.print(x + " "); res = 0; } else { queue.add(x); // 未达阈值,重新入队 } } }
}
2. 最大公约数(辗转相除法)
问题描述:求两个数的最大公约数(GCD)。
核心思路:利用递归,用较大数除以较小数取余数,重复此过程直到余数为 0,此时的除数即为最大公约数。
// 递归实现辗转相除法
public static int gcdRecursive(int a, int b) { if (b == 0) { // 终止条件:当b为0时,a即为最大公约数 return a; } return gcdRecursive(b, a % b); // 递归调用:用b和a%b继续计算
}
3. 奇妙数字
问题描述:找到一个数字,其平方和立方恰好包含 0~9 这 10 个数字各一次。
核心思路:枚举数字,计算其平方和立方,拼接后检查是否包含所有数字且无重复。
package test; import java.util.HashSet; public class Main { public static void main(String[] args) { int num = 1; while (true) { HashSet<Character> set = new HashSet<>(); long square = (long) num * num; long cube = (long) num * num * num; String s = square + "" + cube; if (s.length() == 10) { // 总长度需为10(0~9共10个数字) for (char c : s.toCharArray()) { set.add(c); } if (set.size() == 10) { // 包含所有数字且无重复 System.out.println(num); // 答案:69 break; } } num++; } }
}
二、字符串处理问题
1. ABC 问题
问题描述:输入三个整数和一个由 A、B、C 组成的字符串,按字符串中字母的顺序输出排序后的三个整数(A 对应最小,B 对应中间,C 对应最大)。
核心思路:先排序整数,再根据字符串中字母与索引的映射(A→0,B→1,C→2)输出对应值。
package test; import java.util.Arrays;
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int[] a = new int[3]; for (int i = 0; i < 3; i++) { a[i] = scanner.nextInt(); } Arrays.sort(a); // 排序数组(升序) char[] c = scanner.next().toCharArray(); for (char ch : c) { System.out.print(a[ch - 'A'] + " "); // 映射字母到索引(A→0,B→1,C→2) } }
}
2. 字符串压缩
问题描述:将连续重复的字符压缩为 “字符 + 重复次数”(如 “aaabbb”→“a3b3”),若压缩后长度未缩短则输出原字符串。
核心思路:遍历字符串,计数连续重复字符,拼接字符和次数。
import java.util.Scanner; public class StringCompression { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String input = scanner.nextLine(); String compressed = compress(input); if (compressed.length() < input.length()) { System.out.println(compressed); } else { System.out.println(input); } } public static String compress(String s) { StringBuilder sb = new StringBuilder(); int count = 1; for (int i = 1; i < s.length(); i++) { if (s.charAt(i) == s.charAt(i - 1)) { count++; } else { sb.append(s.charAt(i - 1)); if (count > 1) sb.append(count); count = 1; } } // 处理最后一个字符 sb.append(s.charAt(s.length() - 1)); if (count > 1) sb.append(count); return sb.toString(); }
}
3. 自定义字符串排序(拼接最大数)
问题描述:将一组整数拼接为最大的数(如 [3, 30]→“330”)。
核心思路:将整数转为字符串,按 “b+a” 与 “a+b” 的字典序排序(确保大的组合在前)。
import java.util.Arrays;
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int n = scan.nextInt(); String[] strArr = new String[n]; for (int i = 0; i < n; i++) { strArr[i] = String.valueOf(scan.nextInt()); } // 排序规则:b+a 比 a+b 大则 b 在前 Arrays.sort(strArr, (a, b) -> (b + a).compareTo(a + b)); StringBuilder result = new StringBuilder(); for (String s : strArr) { result.append(s); } System.out.println(result); }
}
三、数字特征问题
1. 包含特定数字的和
问题描述:计算 1~n 中包含数字 2、0、1、9 的所有数的和。
核心思路:两种方法:①逐位拆解数字检查;②转为字符串检查是否包含目标字符。
// 方法1:逐位检查
package test; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int sum = 0; for (int i = 1; i <= n; i++) { if (containsSpecialDigit(i)) { sum += i; } } System.out.println(sum); } private static boolean containsSpecialDigit(int num) { while (num > 0) { int digit = num % 10; if (digit == 2 || digit == 0 || digit == 1 || digit == 9) { return true; } num /= 10; } return false; }
}// 方法2:字符串检查
public static boolean contains(int num) { String s = String.valueOf(num); return s.contains("2") || s.contains("0") || s.contains("1") || s.contains("9");
}
2. 立方数末尾为自身
问题描述:找到 1~10000 中所有满足 “n 的立方的末尾几位等于 n” 的数(如 4³=64,末尾 1 位是 4)。
核心思路:计算 n 的立方,转为字符串后检查是否以 n 为后缀。
package test; public class Main { public static void main(String[] args) { int count = 0; for (int n = 1; n <= 10000; n++) { long cube = (long) n * n * n; if (String.valueOf(cube).endsWith(String.valueOf(n))) { count++; } } System.out.println(count); // 答案:25 }
}
四、其他经典问题
1. 切割长方形(求正方形数量)
问题描述:将长方形切割为若干正方形,每次从最长边切割,求总数量。
核心思路:类似辗转相除法,用长边除以短边得正方形数量,剩余部分继续切割。
public class Main { public static void main(String[] args) { int length = 2019, width = 324; int count = 0; while (length > 0 && width > 0) { count += length / width; // 当前长边可切出的正方形数量 int temp = length % width; length = width; width = temp; // 交换继续切割剩余部分 } System.out.println(count); // 答案:21 }
}
2. 第 N 个质数
问题描述:找到第 2019 个质数(质数:大于 1 的自然数,除了 1 和自身无其他因数)。
核心思路:从 2 开始枚举,判断每个数是否为质数,累计到第 2019 个时输出。
package test; import java.util.ArrayList; public class Main { public static void main(String[] args) { ArrayList<Integer> primes = new ArrayList<>(); int num = 2; while (primes.size() < 2019) { if (isPrime(num)) { primes.add(num); } num++; } System.out.println(primes.get(2018)); // 第2019个(索引2018) } private static boolean isPrime(int n) { if (n < 2) return false; for (int i = 2; i * i <= n; i++) { if (n % i == 0) return false; } return true; }
}
五、逻辑推理问题
谁做了作业
问题描述:5 个学生(A、B、C、D、E)中,根据条件推断谁做了作业:
- A 和 B 要么都做,要么都不做;
- B 和 C 只有一人做;
- D 没做;
- C 和 E 最多一人做。
核心思路:枚举所有可能(0 = 没做,1 = 做了),筛选符合条件的组合。
package test; public class Main { public static void main(String[] args) { for (int a = 0; a <= 1; a++) { for (int b = 0; b <= 1; b++) { for (int c = 0; c <= 1; c++) { for (int d = 0; d <= 1; d++) { for (int e = 0; e <= 1; e++) { // 检查条件 if (a == b // A和B一致 && (b + c) == 1 // B和C仅一人做 && d == 0 // D没做 && (c + e) <= 1) { // C和E最多一人做 // 输出做了作业的人 System.out.println("做了作业的学生:"); if (a == 1) System.out.print("A "); if (b == 1) System.out.print("B "); if (c == 1) System.out.print("C "); if (e == 1) System.out.print("E "); } } } } } } }
}