1.九宫幻方
输入:
0 7 2 0 5 0 0 3 0
输出:
6 7 2 1 5 9 8 3 4
1.1思路分析
- dfs暴力枚举(此方法超时,原因是:用dfs求9个数的全排列需要的时间复杂度太大)
题目要求我们列举出满足要求的九宫幻方,那么我们就用dfs求出所有可能的九宫,再添加条件:横竖斜所有数字加起来都满足相等的条件,把这些满足的九宫幻方放入一个集合中,最后我们枚举集合中的每一个幻方排列,和输入的数进行比较,如果当前数为0,则continue,如果当前数与枚举数相同,则continue;直到当前数不为零,且与枚举数也不相等时,说明这个枚举的幻方与给定的幻方不匹配,那么我们继续枚举下一个幻方。
1.2代码
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class Main {
static boolean[] vis = new boolean[10];
static List<List<Integer>> res = new LinkedList<>();
static List<Integer> list=new LinkedList<>();
//static List<List<Integer>> ans=new LinkedList<>();
public static void main(String[] args) {
int[] arr=new int[9];
int count=0;
boolean flag=true;
Scanner sc=new Scanner(System.in);
for(int i=0;i<arr.length;i++){
arr[i]=sc.nextInt();
}
int index=0;
dfs(1);
for(List<Integer> list1:res){
flag=true;
for(int i=0;i<list1.size();i++){
if(arr[i]==0) continue;
if(arr[i]==list1.get(i))continue;
if(arr[i]!=0&&arr[i]!=list1.get(i)){
flag=false;
}
}
if(flag){
index=res.indexOf(list1);
count++;
}
}
if(count==1){
System.out.println(res.get(index).get(0)+" "+res.get(index).get(1)+" "+res.get(index).get(2));
System.out.println(res.get(index).get(3)+" "+res.get(index).get(4)+" "+res.get(index).get(5));
System.out.println(res.get(index).get(6)+" "+res.get(index).get(7)+" "+res.get(index).get(8));
}else if(count>1){
System.out.println("Too Many");
}
}
public static void dfs(int n) {
if (list.size()==9) {
if(ismatch(list)) {
res.add(new LinkedList<>(list));
}
return;
}
for (int i = 1; i < 10; i++) {
if (vis[i]) {
continue;
}
vis[i] = true;
list.add(i);
dfs(n + 1);
list.remove(list.size()-1);
vis[i] = false;
}
}
public static boolean ismatch(List<Integer> list){
return list.get(0)+list.get(1)+list.get(2)==15&&
list.get(3)+list.get(4)+list.get(5)==15&&
list.get(6)+list.get(7)+list.get(8)==15&&
list.get(0)+list.get(4)+list.get(8)==15&&
list.get(2)+list.get(4)+list.get(6)==15&&
list.get(0)+list.get(3)+list.get(6)==15&&
list.get(1)+list.get(4)+list.get(7)==15&&
list.get(2)+list.get(5)+list.get(8)==15;
}
}
2.拉马车
2.1思路分析
很典型的模拟题,数据结构题目中已经给我们暗示了,为了正确的将重复字符与其之间的字符放入各牌组的末尾,我们可以用一个栈来保存已经出过了牌,如果在栈中遇到了重复的元素,那么依次弹出栈并加入各牌组末尾即可,如果没有重复元素,那么直接入栈,并由另一个牌组出牌。
题主在此题踩了大坑,清楚是模拟,但是摸不清一种情况:一个牌组连续摸到相同牌。导致逻辑混乱处理不清,200分钟只能堪堪过一个测试用例(真是菜狗啊)。
2.2代码
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;
public class Main008_拉马车 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String a = in.nextLine();
String b = in.nextLine();
int len = a.length()+b.length();
Queue<Character> queue1 = new LinkedList<Character>();
Queue<Character> queue2 = new LinkedList<Character>();
Stack<Character> stack = new Stack<Character>();
// 字符串中字符的入队操作
for(int i=0;i<a.length();i++)
queue1.offer(a.charAt(i));
for(int i=0;i<b.length();i++)
queue2.offer(b.charAt(i));
Boolean Awin = true; // 初始和A赢牌时A先出牌
int count = 0 ; // 计数双方一共出牌多少次,当count过大时返回 -1
while(!queue1.isEmpty() && !queue2.isEmpty()) {
count++;
if(count==10000) break; // 当达到10000次,说明存在死循环,即跳出循环,返回-1
if(Awin==true) { //初始和A赢牌时A先出牌
if(stack.contains(queue1.peek())) { //判断栈中是否包含队首元素
Awin = true; //包含,则A局部获胜,Awin=true;
char t = queue1.poll(); // 记录队首元素,并出队
queue1.offer(t); // 将元素添加至队尾
while(stack.peek()!=t) // 将两个相同元素之间的栈中的元素添加至队尾
queue1.offer(stack.pop());
queue1.offer(stack.pop()); //将栈中和队首相同的元素添加中队尾
}else {
stack.push(queue1.poll()); //栈中不包含队首元素
Awin = false; // Awin=false; 下次B出牌
}
// 注释同上
}else {
if(stack.contains(queue2.peek())) {
Awin = false; // stack中存在元素和B出牌的元素相同时,则B收牌,下次B先出牌
char t = queue2.poll();
queue2.offer(t);
while(stack.peek()!=t) {
queue2.offer(stack.pop());
}
queue2.offer(stack.pop());
}else {
stack.push(queue2.poll());
Awin = true;
}
}
}
StringBuffer sb = new StringBuffer();
if(queue2.isEmpty()) {
int size = queue1.size();
for(int i=0;i<size;i++) // queue.size();每出队一次变化一次,so应提前记录
sb.append(queue1.poll());
System.out.println(sb.toString());
}else if(queue1.isEmpty()) {
int size = queue2.size();
for(int i=0;i<size;i++)
sb.append(queue2.poll());
System.out.println(sb.toString());
}else if(count==10000) // 循环10000次内,未分胜负,则认为死循环,输出-1
System.out.println(-1);
}
}
3.K倍区间
输入:
5 2 1 2 3 4 5
输出
6
3.1思路分析
- 最容易想到的是暴力解法,两个指针,每次移动就计算依次区间和,满足K倍区间的要求,那么count++。
- 暴力解法很明显,面对1e5的数据,很容易超时,因此我们需要一个优化技巧来降低时间复杂度,这个就是前缀和,根据构建前缀和数组,那么时间复杂度将降到O(n2)
3.2代码
- 暴力 ```java import java.util.LinkedList; import java.util.List; import java.util.Scanner;
public class Main4 { //暴力法
public static void main(String[] args) {
List<Integer> list=new LinkedList<>();
Scanner sc=new Scanner(System.in);
int N=sc.nextInt();
int K=sc.nextInt();
int ans=0;
sc.nextLine();
for(int i=0;i<N;i++){
list.add(sc.nextInt());
}
for(int i=0;i<list.size();i++){
for(int j=i;j< list.size();j++){
if(sum(list,i,j)%K==0){
ans++;
}
}
}
System.out.println(ans);
}
public static int sum(List<Integer> list,int i,int j){
int sum=0;
for(;i<=j;i++){
sum+=list.get(i);
}
return sum;
}
}
- 构建前缀和数组
```java
public class Main4 { //前缀和
public static void main(String[] args) {
List<Integer> list = new LinkedList<>();
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int K = sc.nextInt();
int[] arr=new int[N];
int[] next=new int[N+1];
next[0]=0;
int sum=0;
sc.nextLine();
int ans = 0;
for (int i = 0; i < N; i++) {
arr[i]=sc.nextInt();
}
for(int i=1;i<next.length;i++){
sum+=arr[i-1];
next[i]=sum;
//System.out.println(next[i]);
}
for(int i=0;i<next.length;i++){
for(int j=i+1;j<next.length;j++){
if((next[j]-next[i])%K==0){
ans++;
}
}
}
System.out.println(ans);
}
}
4.分巧克力
输入:
2 10 6 5 5 6
输出:
2
4.1思路分析
1.最直观的方法就是暴力法,已知一个巧克力的长(HI)和宽(WI),那么我们从中可以切出的正方形数量,按照上述测试用例来说,HI=6,WI=5,那么可以切出边长为1的正方形=HI/6WI/5=30,边长为2的正方形=HI/6WI/5=3*2=6。一遍一遍的枚举,如果能切出的数量>=K,那么就更新一下能够切出的最大边长。
4.2代码
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class Main5 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int N=sc.nextInt();
int K=sc.nextInt();
int res=1;
sc.nextLine();
List<Integer>[] list=new LinkedList[N];
for(int i=0;i<list.length;i++){
list[i]=new LinkedList<>();
list[i].add(sc.nextInt());
list[i].add(sc.nextInt());
}
//从边长为1开始切分
for(int i=1;i<10000;i++){
int count=0;
for(int j=0;j< list.length;j++){
int HI=list[j].get(0);
int WI=list[j].get(1);
count+=HI/i*WI/i;
}
if(count>=K)res=Math.max(res,i);
}
System.out.println(res);
}
}