题目描述
玛雅人有一种密码,如果字符串中出现连续的2012四个数字就能解开密码。给一个长度为N的字符串,(2=<N<=13)该字符串中只含有0,1,2三种数字,问这个字符串要移位几次才能解开密码,每次只能移动相邻的两个数字。例如02120经过一次移位,可以得到20120,01220,02210,02102,其中20120符合要求,因此输出为1.如果无论移位多少次都解不开密码,输出-1。
输入描述:
输入包含多组测试数据,每组测试数据由两行组成。
第一行为一个整数N,代表字符串的长度(2<=N<=13)。
第二行为一个仅由0、1、2组成的,长度为N的字符串。
输出描述:
对于每组测试数据,若可以解出密码,输出最少的移位次数;否则输出-1。
示例1
输入
复制
5
02120
输出
复制
1
解法一:回溯法
有误,只能通过百分之90
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
//13
//1122121122200
public class Main
{
public static void main(String[] args)
{
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
try {
String str;
while((str=br.readLine())!=null) {
int len = Integer.parseInt(str);
String mode = br.readLine();
char[] ch = mode.toCharArray();
if(mode.indexOf("2012") != -1) System.out.println("0");
else if(!isVaild(mode)) System.out.println("-1");
else {
int[]res = {len*len};
backtrack(res, ch, len-1, 0);
System.out.println(res[0]);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void backtrack(int[] res, char[] ch, int n, int count) {
if(new String(ch).indexOf("2012") != -1) {
if(count < res[0]) res[0] = count;
return;
}
for (int i = n; i > 0; i--) {
// in the current permutation
swap(ch, i, i-1);
count++;
// use next integers to complete the permutations
backtrack(res, ch, i-1, count);
// backtrack
swap(ch, i, i-1);
count--;
}
}
public static void swap(char[] ch, int i, int j) {
char temp = ch[i];
ch[i] = ch[j];
ch[j] = temp;
}
public static boolean isVaild(String str) {//只有字符串中同时含有0,1,2时才有可能通过位移产生2012
boolean b0 = false;
boolean b1 = false;
boolean b2 = false;
for(char c : str.toCharArray()) {
if(c == '0') {
b0 = true;
}else if(c == '1') {
b1 = true;
}else if(c == '2') {
b2 = true;
}else {
return false;
}
}
return b0&&b1&&b2;
}
}
解法二:bfs,从别人那看来的,超级牛逼
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
public class Main
{
public static Queue<String> q = new LinkedList<>();
public static Map<String, Integer> map = new HashMap<>();
public static void main(String[] args)
{
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
try {
String str;
while((str=br.readLine())!=null) {
String mode = br.readLine();
char[] ch = mode.toCharArray();
if(mode.indexOf("2012") != -1) System.out.println("0");
else if(!isVaild(mode)) System.out.println("-1");
else System.out.println(BFS(mode));
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static int BFS(String str) {
q.add(str);//初始字符串作为起点放入队列
map.put(str, 0);//初始字符串经历的交换次数是0
while(!q.isEmpty()) {
str = q.poll();//取出队首,存入str
for(int i = 0; i < str.length()-1; i++) {//尝试进行一次交换
char[] ch = str.toCharArray();
swap(ch, i, i+1);//新字符串由str交换i位和i+1位得到
String newStr = new String(ch);
if(!map.containsKey(newStr)){//如果这个字符串没出现过
map.put(newStr, map.get(str)+1);//现在出现过了,且交换次数比他爹多1
if(newStr.indexOf("2012") != -1) return map.get(newStr);//符合要求,收工
else q.add(newStr);//不合要求,那继续bfs,把它加入队列
}
else continue;//出现过的字符串,不用进行处理
}
}
return -1;//遍历完成,没发现符合要求的字符串,返回-1
}
public static void swap(char[] ch, int i, int j) {
char temp = ch[i];
ch[i] = ch[j];
ch[j] = temp;
}
public static boolean isVaild(String str) {//只有字符串中同时含有0,1,2时才有可能通过位移产生2012
boolean b0 = false;
boolean b1 = false;
boolean b2 = false;
for(char c : str.toCharArray()) {
if(c == '0') {
b0 = true;
}else if(c == '1') {
b1 = true;
}else if(c == '2') {
b2 = true;
}else {
return false;
}
}
return b0&&b1&&b2;
}
}
来源:CSDN
作者:东山阿强
链接:https://blog.csdn.net/weixin_43306331/article/details/104147049