You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
5.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import java.util.List;
import java.util.Random;
/**
* 负责生成并添加括号
*/
public class BracketManager {
private static final Random RANDOM = new Random();
/**
* 根据元素个数选择括号对数
* 3 -> 80% 1对 20%0对
* 4 -> 90% 1对 10%2对
* 5 -> 50% 1对 50%2对
*/
public int decideParenthesesPairs(int numCount) {
return switch (numCount) {
case 3 -> RANDOM.nextDouble() < 0.8 ? 1 : 0;
case 4 -> RANDOM.nextDouble() < 0.9 ? 1 : 2;
case 5 -> RANDOM.nextDouble() < 0.5 ? 1 : 2;
default -> 0;
};
}
// 添加括号
public String addParentheses(String expression, int pairs, List<Integer> numPositions) {
String[] tokens = expression.split(" ");
int numCount = numPositions.size();
boolean[] markLeft = new boolean[numCount];
boolean[] markRight = new boolean[numCount];
generateBracketPositions(numCount, numPositions, pairs, tokens, markLeft, markRight);
String result = insertBrackets(tokens, markLeft, markRight);
return validateParentheses(result) ? result : expression;
}
//计算生成括号的位置
private void generateBracketPositions(int numCount, List<Integer> numPositions, int pairs, String[] tokens,
boolean[] markLeft, boolean[] markRight) {
int attempts = 0;
for (int p = 0; p < pairs && attempts < 50; p++, attempts++) {
boolean placed = false;
for (int tries = 0; tries < 50 && !placed; tries++) {
int start = RANDOM.nextInt(numCount - 1);
int end = start + 1 + RANDOM.nextInt(numCount - start - 1);
if (end >= numCount) end = numCount - 1;
// 20%概率尝试嵌套在已有括号内部
if (RANDOM.nextDouble() < 0.2) {
for (int i = 0; i < numCount; i++) {
if (markLeft[i]) {
start = i;
end = i + RANDOM.nextInt(numCount - i);
break;
}
}
}
if (canPlaceBracket(start, end, markLeft, markRight, numPositions, tokens)) {
markLeft[start] = true;
markRight[end] = true;
placed = true;
}
}
}
}
//检测添加括号的合法性
private boolean canPlaceBracket(int start, int end, boolean[] markLeft, boolean[] markRight,
List<Integer> numPositions, String[] tokens) {
if (isOuterMostBracket(start, end, markLeft.length)) return false;
if (isInvalidOverlap(start, end, markLeft, markRight)) return false;
return isValidBracketRange(tokens, numPositions, start, end);
}
//避免最外层括号
private boolean isOuterMostBracket(int start, int end, int numCount) {
return start == 0 && end == numCount - 1;
}
//允许嵌套但禁止交叉
private boolean isInvalidOverlap(int start, int end, boolean[] markLeft, boolean[] markRight) {
for (int i = start; i <= end; i++) {
// start/end可重合内部禁止已有左右括号
if ((i != start && markLeft[i]) || (i != end && markRight[i])) return true;
}
return false;
}
//检测括号是否有意义(优先级)
private boolean isValidBracketRange(String[] tokens, List<Integer> numPositions, int start, int end) {
int opStart = numPositions.get(start) + 1;
int opEnd = numPositions.get(end) - 1;
String firstOp = null;
boolean hasHigherOuterOp = false;
for (int i = opStart; i <= opEnd; i += 2) {
if (!isNumber(tokens[i])) {
if (firstOp == null) firstOp = tokens[i];
else if (isDifferentPriority(firstOp, tokens[i])) {
hasHigherOuterOp = true;
break;
}
}
}
return hasHigherOuterOp || firstOp == null;
}
//比较运算符优先级
private boolean isDifferentPriority(String op1, String op2) {
int p1 = (op1.equals("+") || op1.equals("-")) ? 1 : 2;
int p2 = (op2.equals("+") || op2.equals("-")) ? 1 : 2;
return p1 != p2;
}
//插入操作
private String insertBrackets(String[] tokens, boolean[] markLeft, boolean[] markRight) {
StringBuilder sb = new StringBuilder();
int numIndex = 0;
for (String token : tokens) {
if (isNumber(token)) {
if (markLeft[numIndex]) sb.append("( ");
sb.append(token);
if (markRight[numIndex]) sb.append(" )");
numIndex++;
} else {
sb.append(" ").append(token).append(" ");
}
}
return sb.toString();
}
//检查括号是否缺失
private boolean validateParentheses(String expr) {
int balance = 0;
for (char c : expr.toCharArray()) {
if (c == '(') balance++;
if (c == ')') balance--;
if (balance < 0) return false;
}
return balance == 0;
}
private boolean isNumber(String token) {
try { Integer.parseInt(token); return true; }
catch (NumberFormatException e) { return false; }
}
}