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过大时返回 -1while(!queue1.isEmpty() && !queue2.isEmpty()) {count++;if(count==10000) break; // 当达到10000次,说明存在死循环,即跳出循环,返回-1if(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次内,未分胜负,则认为死循环,输出-1System.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;}
}
- 构建前缀和数组```javapublic 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);}}

