题目来源于:卡码网KamaCoder
题解来源于:GitHub - youngyangyang04/kamacoder-solutions: 卡码网题解全集
字符串解压缩
给定一个被压缩过的字符串,压缩规则如下: 对于字符串中连续的m个相同字符串S将会压缩为[m|S](m为一个整数且0<=m<=100),例如字符串ABCABCABC将会被压缩为[3|ABC]。
你的任务是解压被压缩过的字符串。
样例输入
"HG[3|B[2|CA]]F"
样例输出
"HGBCACABCACABCACAF"
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Scanner;
/**
* @author light
* @Description 字符串解压缩
*
* 给定一个被压缩过的字符串,压缩规则如下:
* 对于字符串中连续的m个相同字符串S将会压缩为[m|S](m为一个整数且0<=m<=100),
* 例如字符串ABCABCABC将会被压缩为[3|ABC]。
* 你的任务是解压被压缩过的字符串。
*
* (思路:利用栈/指针(利用递归的思想
* @create 2023-08-17 4:53
*/
public class n1 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
String s=input.nextLine(); //考虑字符串中有空格的情况
//我的思路:利用栈:卡玛网两个案例未通过 通过案例数:7/9 待解决
//s=stringDecompression(s);
//卡玛网题解
s=decode(s)
System.out.println(s);
}
//利用栈
public static String stringDecompression(String s){
Deque<Character> stack=new ArrayDeque<>();
if(s==null){
return "";
}
for (int i = 0; i < s.length(); i++) {
char ch=s.charAt(i);
if (ch!=']'){
stack.push(ch);
}else{
Deque<Character> stackOut=new ArrayDeque();
while(stack.peek()!='|'){
stackOut.push(stack.pop());
}
stack.pop(); //出栈的是'|'
int count=stack.pop()-'0';
StringBuilder sb=new StringBuilder();
while(!stackOut.isEmpty()){
sb.append(stackOut.removeLast());
}
String s1=sb.toString();
StringBuilder sb1=new StringBuilder();
for(int j=1;j<=count;j++){
sb1.append(s1); //解压缩
}
s1=sb1.toString();
for (int j = 0; j < s1.length(); j++) {
char c=s1.charAt(j);
stackOut.push(c);
}
if(stack.pop()=='['){
while(!stackOut.isEmpty()){
stack.push(stackOut.pop());
}
}
}
}
StringBuilder sb=new StringBuilder();
while(!stack.isEmpty()){
sb.append(stack.removeLast());
}
return sb.toString();
}
//利用递归
public static String decode(String s){
int x=-1,y=-1,z=-1;
int i=0;
//第一次递归找最里面的三个分隔符
while(i<s.length()){
if(s.charAt(i)=='['){
x=i;
} else if (s.charAt(i)=='|') {
y=i;
} else if (s.charAt(i)==']') {
z=i;
break;
}
i++;
}
if(x!=-1&&y!=-1&&z!=-1){
int items= Integer.parseInt(s.substring(x+1,y));
String sub=s.substring(y+1,z);
StringBuilder sb=new StringBuilder();
for (int j = 1; j <=items ; j++) {
sb.append(sub);
}
String decodeStr=s.substring(0,x)+sb.toString()+s.substring(z+1);
return decode(decodeStr);
}
return s;
}
}
子矩形的最大面积
给定一个矩形,宽度为 W,高度为 H,现需要对其进行划分。现有一个数组 yCutting 用于表示在水平方向上用于切分矩形的切线位置,另有一个数组 xCutting 表示在垂直方向上用于切分矩形的切线位置。
求被切割后的所有子矩形中最大的那块的面积。
输入
第一行 H:矩形的高度
第二行 W:矩形的宽度
第三行:yCutting 数组的长度
第四行:yCutting 数组
第五行:xCutting 数组的长度
第六行:xCutting 数组
输出
一个整数,表示最大的那块子矩形的面积。
样例输入
5
4
3
1 2 4
2
1 3
样例输出
4
import java.util.Arrays;
import java.util.Scanner;
/**
* @author light
* @Description 子矩形的最大面积
*(思路:首先读取输入数据,然后对水平和垂直切割数组进行排序,并
* 利用辅助函数 getMaxInterval 计算每个方向上切割区间的最大值。
* 最终,将两个方向上的最大切割区间相乘即得到最大子矩形的面积。
* @create 2023-08-17 6:03
*/
public class n3 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
//获取矩形高度
int h=input.nextInt();
//获取矩形宽度
int w=input.nextInt();
//yCutting 数组的长度及内容
int y= input.nextInt();
int[] yCutting=new int[y];
for (int i = 0; i < y; i++) {
yCutting[i]=input.nextInt();
}
//xCutting 数组的长度及内容
int x= input.nextInt();
int[] xCutting=new int[x];
for (int i = 0; i < x; i++) {
xCutting[i]=input.nextInt();
}
//对切割点进行排序
Arrays.sort(yCutting);
Arrays.sort(xCutting);
//获取水平切割区间最大值
int maxYInterval=getMaxInterval(yCutting,w);
//获取垂直切割区间最大值
int maxXInterval=getMaxInterval(xCutting,h);
//计算最大子矩形面积
int maxArea=maxXInterval*maxYInterval;
System.out.println(maxArea);
}
private static int getMaxInterval(int[] cuttingArray, int dimension) {
int interval=cuttingArray[0]; //获取首边界到第一条割线的距离
for (int i = 1; i < cuttingArray.length; i++) {
interval=Math.max(interval,cuttingArray[i]-cuttingArray[i-1]);
}
//dimension-cuttingArray[cuttingArray.length-1]:最后一条割线到尾边界的距离
interval=Math.max(interval,dimension-cuttingArray[cuttingArray.length-1]);
return interval;
}
}
逛街
小明在周末的时候和他的小伙伴来到大城市逛街,一条步行街上有很多高楼,共有 n 座高楼排成一行。
小明从第一栋一直走到了最后一栋,小明从来都没有见到这么多的楼,所以他想知道他在每栋楼的位置处能看到多少栋楼呢?(当前面的楼的高度大于等于后面的楼时,后面的楼将被挡住)
输入
输入一个数组,表示每栋楼的高度。
输出
输出一个数组,表示在每栋楼对应的位置上能看到多少栋楼。
样例输入
[5,3,8,3,2,5]
样例输出
[3,3,5,4,4,4]
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.Scanner;
/**
* @author light
* @Description 逛街
*
*
* (思路:
* 题目中要求从两个方向看,从左向右遍历和从右向左遍历,考虑使用单调栈
* 首先定义一个数组存放结果;将 visibleCounts 每个位置上的值加 1(因为包括自己本身的楼)。
* **从左向右遍历高楼时,定义一个栈stack1,栈中存放已经经过的高楼,保证栈顶元素始终比后面元素高;
* 遍历过程中,对于每一栋楼,将当栈中大小加到对应楼visibleCounts的下标处;表示向左看的楼数
*
* **从右向左遍历高楼时,定义一个栈stack2,栈中存放已经经过的高楼,保证栈顶元素始终比后面元素高;
* 遍历过程中,对于每一个元素,将当前栈的大小加到对应楼visibleCounts的下标出,表示向右看的楼数
* @create 2023-08-17 6:04
*/
public class n4 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
//String[] buildings = input.next().split(",");
//int[] height=new int[buildings.length];
//for (int i = 0; i < height.length; i++) {
// height[i]=Integer.parseInt(buildings[i]);
//}
String buildings=input.next();
int[] height=parseIntArray(buildings);
int[] visibleCounts=new int[height.length];
Arrays.fill(visibleCounts,1); //先自加1,表示楼本身
findVisibleCounts(height,visibleCounts);
System.out.println(Arrays.toString(visibleCounts).replaceAll(" ",""));
}
public static void findVisibleCounts(int[] height,int[] visibleCounts){
Deque<Integer> stack1=new ArrayDeque<>(); //存放从左向右遍历的楼数:表示向左看
Deque<Integer> stack2=new ArrayDeque<>();//存放从右向左遍历的楼数:表示向右看
for (int i = 0; i < height.length; i++) {
visibleCounts[i]+=stack1.size();
while(!stack1.isEmpty()&&stack1.peek()<=height[i]){
stack1.pop();
}
stack1.push(height[i]);
}
for (int i = height.length-1; i >=0 ; i--) {
visibleCounts[i]+=stack2.size();
while(!stack2.isEmpty()&&stack2.peek()<=height[i]){
stack2.pop();
}
stack2.push(height[i]);
}
}
private static int[] parseIntArray(String buildings) {
String[] s=buildings.substring(1,buildings.length()-1).split(",");
int[] height=new int[s.length];
for (int i = 0; i < height.length; i++) {
height[i]=Integer.parseInt(s[i].trim());
}
return height;
}
}