第一题:输入两个长度相同且全由小写字符组成的字符串,遍历两个字符串,如果当前位置的两个字符相同,将他们转换为大写;如果不同这保留,最后输出变换之后的字符串。
/**
* @Author: ShuWang Li
* @Date: 2025/3/19 11:06
* @Description: 字符串的变换
**/
public class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String s1 = in.next();
String s2 = in.next();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < n; i++){
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if(c1 == c2){
sb.append(Character.toUpperCase(c1));
}else{
sb.append((char)Math.max(c1, c2));
}
}
System.out.println(sb.toString());
in.close();
}
}
第二题:
第一行输入 n-1 个由 0和1组成的数字字符串,第二行输出有1到n之间的数字组成的序列,如果第一行下标为i的位置的数字为0的话,第二行输出下标为i + 1的数字应该就比下标为i的数字小,如果第一行下标为1的位置数字为1,第二行下标为i+1的数字就比i位置的数字大。以下是例子:
0101
3 2 4 1 5
答案:
/**
* @Author: ShuWang Li
* @Date: 2025/3/24 11:46
* @Description: 根据当前位置的值与上一个位置大小关系构建数组
**/
public class SequenceRearrangement {
public static int[] rearrangeSequence(String s) {
// n 是序列的长度,由输入的字符串 s 的长度加 1 得到
int n = s.length() + 1;
// 创建一个长度为 n 的数组 seq,存储从 1 到 n 的数字
int[] seq = new int[n];
for (int i = 0; i < n; i++) {
seq[i] = i + 1; // 初始化 seq 数组为 [1, 2, 3, ..., n]
}
// 使用栈来帮助我们根据条件调整数字顺序
Stack<Integer> stack = new Stack<>();
// 结果数组,用来存放最终排列好的数字
int[] result = new int[n];
int index = 0; // 用于在结果数组中插入元素的索引
// 遍历字符串 s 的每一位,检查相邻数字之间的大小关系
for (int i = 0; i < n - 1; i++) {
stack.push(seq[i]); // 将当前数字 seq[i] 压入栈
// 如果当前字符是 '1',表示当前数字 seq[i] 要小于下一个数字 seq[i+1]
// 此时我们将栈中的数字按逆序输出,因为 seq[i+1] 必须比 seq[i] 大
if (s.charAt(i) == '1') {
// 将栈中的元素逆序弹出并放入结果数组,形成一个递增的顺序
while (!stack.isEmpty()) {
result[index++] = stack.pop(); // 将栈中的元素逆序添加到结果中
}
}
}
// 最后,将最后一个数字 seq[n-1] 压入栈
stack.push(seq[n - 1]);
// 最后,弹出栈中的所有元素(确保按照从大到小的顺序处理)
while (!stack.isEmpty()) {
result[index++] = stack.pop(); // 将栈中的元素逆序放入结果数组
}
// 返回最终排列好的数字序列
return result;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int[] result = rearrangeSequence(s);
// 打印结果
for (int num : result) {
System.out.print(num + " ");
}
}
}
第三题:
第一行输入一个整数 n 代表接下来输入的数字的个数,第二行输入n个数字,其中x和y可以这些数字当中的两个,其中x和y的位置为这些数字,并且x要在y的左边,找出满足|x - y| = |x| - |y|的个数。例如
输入:
6
1 1 4 5 1 4
输出:
7
解法1:暴力求解: 时间复杂度O(n^2)
public class SequenceRearrangement {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = scanner.nextInt();
}
System.out.println(countValidPairs(nums));
}
public static int countValidPairs(int[] nums) {
int count = 0;
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
int x = nums[i], y = nums[j];
if(x * y > 0 && Math.abs(x) >= Math.abs((y)) || y == 0) {
count++;
}
}
}
return count;
}
}
解法2:分治法+树状dp:时间复杂度O(nlogn)
/**
* @Author: ShuWang Li
* @Date: 2025/3/24 11:46
* @Description: 具体来说,给定一个数组,我们需要找到所有满足以下条件的对 (i, j)(其中 i < j):
* 1. |a[i] - a[j]| = |a[i]| - |a[j]|
*
* 该程序通过将数字分为正数、负数和零三类来优化匹配过程,减少了暴力匹配的计算量。
*/
public class SequenceRearrangement {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 输入数组的大小
int n = sc.nextInt();
int[] nums = new int[n];
// 输入n个整数
for (int i = 0; i < n; i++) {
nums[i] = sc.nextInt();
}
// 用来存储正数、负数和零
List<Integer> pos = new ArrayList<>(); // 正数列表
List<Integer> neg = new ArrayList<>(); // 负数列表
int zeroCount = 0; // 零的个数
// 遍历数组,按正负零分类
for (int num : nums) {
if (num > 0) {
pos.add(num); // 如果是正数,加入正数列表
} else if (num < 0) {
neg.add(num); // 如果是负数,加入负数列表
} else {
zeroCount++; // 如果是零,零的数量加一
}
}
// 计算正数对的数量
int countPos = countPairs(pos.stream().mapToInt(i -> i).toArray());
// 计算负数对的数量(将负数转换为正数进行处理)
int[] negAbs = neg.stream().mapToInt(i -> Math.abs(i)).toArray();
int countNeg = countPairs(negAbs);
// 计算零的对数,零的组合数是 C(zeroCount, 2)
int countZero = zeroCount * (zeroCount - 1) / 2;
// 总的满足条件的对数
int total = countPos + countNeg + countZero;
System.out.println(total); // 输出结果
}
/**
* 计算一个数组中满足条件的对 (i, j) 的数量,其中 i < j
* 具体做法:通过二叉索引树(Fenwick Tree)来高效统计每个数字的出现次数
*/
private static int countPairs(int[] nums) {
if (nums.length == 0) {
return 0;
}
// 使用TreeSet去重,确保每个数字在计算时只考虑一次
TreeSet<Integer> unique = new TreeSet<>();
for (int num : nums) {
unique.add(num);
}
// 将去重后的数字排序,并为每个数字生成一个排名
List<Integer> sorted = new ArrayList<>(unique);
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < sorted.size(); i++) {
map.put(sorted.get(i), i + 1); // 映射每个数字到它在排序数组中的位置
}
// 创建一个Fenwick Tree来统计排名
FenwickTree ft = new FenwickTree(sorted.size());
int count = 0;
// 从右到左遍历数组,统计每个数字的出现次数
for (int i = nums.length - 1; i >= 0; i--) {
int num = nums[i];
int rank = map.get(num); // 获取当前数字的排名
count += ft.query(rank); // 查询当前数字排名之前出现的数字对的数量
ft.update(rank, 1); // 更新Fenwick Tree,表示当前数字出现过一次
}
return count; // 返回满足条件的对的数量
}
/**
* Fenwick Tree(也叫Binary Indexed Tree)的实现,用于高效的前缀和查询和更新。
* 这里用于统计数字出现的次数。
*/
static class FenwickTree {
int size;
int[] tree;
public FenwickTree(int size) {
this.size = size;
tree = new int[size + 1]; // 初始化Fenwick Tree数组
}
// 更新树状数组(更新索引为index的元素的值)
public void update(int index, int delta) {
while (index <= size) {
tree[index] += delta; // 增加delta值
index += index & -index; // 移动到父节点
}
}
// 查询前缀和(查询从1到index的和)
public int query(int index) {
int sum = 0;
while (index > 0) {
sum += tree[index]; // 累加当前节点的值
index -= index & -index; // 移动到父节点
}
return sum;
}
}
}